มันเป็นปัญหาหรือไม่ที่จะต้องพึ่งพาระหว่างออบเจ็กต์ของเลเยอร์เดียวกันในสถาปัตยกรรมซอฟต์แวร์แบบเลเยอร์?


12

เมื่อพิจารณาถึงซอฟต์แวร์ขนาดกลางขนาดใหญ่ที่มีสถาปัตยกรรมแบบเลเยอร์ n และการฉีดขึ้นต่อกันฉันรู้สึกสบายใจที่จะพูดว่าวัตถุที่เป็นของเลเยอร์สามารถพึ่งพาวัตถุจากเลเยอร์ที่ต่ำกว่า

แต่ฉันไม่แน่ใจว่าจะคิดอย่างไรเกี่ยวกับวัตถุที่ขึ้นอยู่กับวัตถุอื่นของเลเยอร์เดียวกัน

ตัวอย่างเช่นสมมติว่าแอปพลิเคชันที่มีสามชั้นและวัตถุหลายอย่างเช่นหนึ่งในภาพ เห็นได้ชัดว่าการพึ่งพาจากบนลงล่าง (ลูกศรสีเขียว) ก็โอเคการเติมเงิน (ลูกศรสีแดง) ไม่เป็นไร แต่การพึ่งพาในเลเยอร์เดียวกัน (ลูกศรสีเหลือง) เป็นอย่างไร

ป้อนคำอธิบายรูปภาพที่นี่

ไม่รวมการพึ่งพาอาศัยกันแบบวงกลมฉันอยากรู้เกี่ยวกับปัญหาอื่น ๆ ที่อาจเกิดขึ้นและสถาปัตยกรรมของชั้นที่ถูกละเมิดในกรณีนี้


หากคุณไม่มีวงจรในเลเยอร์ที่คุณมีลิงค์ horysontal มีการแบ่งออกเป็นเลเยอร์ย่อยซึ่งมีการขึ้นต่อกันระหว่างเลเยอร์เท่านั้น
max630

คำตอบ:


10

ใช่วัตถุในชั้นหนึ่งสามารถมีการพึ่งพาโดยตรงระหว่างกันบางครั้งแม้แต่คนที่เป็นวงจร - นั่นคือสิ่งที่ทำให้เกิดความแตกต่างหลักในการพึ่งพาที่ได้รับอนุญาตระหว่างวัตถุในชั้นต่าง ๆ โดยที่ไม่มีการพึ่งพาโดยตรงโดยตรง ทิศทาง

อย่างไรก็ตามนั่นไม่ได้หมายความว่าพวกเขาควรมีการพึ่งพาเช่นนั้นโดยพลการ มันขึ้นอยู่กับว่าเลเยอร์ของคุณเป็นอย่างไรระบบขนาดใหญ่และความรับผิดชอบของชิ้นส่วน โปรดทราบว่า "สถาปัตยกรรมแบบแบ่งชั้น" เป็นคำที่คลุมเครือมีการเปลี่ยนแปลงอย่างมากของความหมายที่แท้จริงในระบบที่แตกต่างกัน

ตัวอย่างเช่นสมมติว่าคุณมี "ระบบเลเยอร์แนวนอน" พร้อมชั้นฐานข้อมูลชั้นธุรกิจและชั้นส่วนติดต่อผู้ใช้ (UI) ให้บอกว่าเลเยอร์ UI มีคลาสไดอะล็อกที่แตกต่างกันอย่างน้อยหลายสิบคลาส

หนึ่งอาจเลือกการออกแบบที่ไม่มีคลาสโต้ตอบขึ้นอยู่กับคลาสไดอะล็อกอื่นโดยตรง หนึ่งอาจเลือกการออกแบบที่มี "กล่องโต้ตอบหลัก" และ "กล่องโต้ตอบย่อย" อยู่และมีเพียงการพึ่งพาโดยตรงจากกล่องโต้ตอบ "หลัก" ถึง "ย่อย" หรืออาจต้องการการออกแบบที่คลาส UI ใด ๆ ที่มีอยู่สามารถใช้ / ใช้คลาส UI อื่น ๆ จากเลเยอร์เดียวกันได้

สิ่งเหล่านี้ล้วนเป็นตัวเลือกในการออกแบบที่อาจเป็นไปได้มากหรือน้อยกว่านั้นขึ้นอยู่กับประเภทของระบบที่คุณกำลังสร้าง


ดำเนินการต่อในตัวอย่าง UI สิ่งที่เป็นมืออาชีพและข้อเสียของการมีการอ้างอิงภายใน? ฉันเห็นว่ามันทำให้การใช้ซ้ำง่ายขึ้นและแนะนำการพึ่งพาแบบวนรอบซึ่งอาจเป็นปัญหาขึ้นอยู่กับวิธี DI ที่ใช้ มีอะไรอีกไหม
bracco23

@ bracco23: ข้อดีและข้อเสียของการพึ่งพา "ภายใน" นั้นเหมือนกับข้อดีของข้อเสียที่มีการพึ่งพาโดยพลการ "จุดด้อย" พวกเขาทำให้ส่วนประกอบยากที่จะนำมาใช้ซ้ำและยากที่จะทดสอบโดยเฉพาะอย่างยิ่งในการแยกออกจากส่วนประกอบอื่น ๆ ข้อดีคือการพึ่งพาอย่างชัดเจนทำให้สิ่งต่าง ๆ ที่ต้องใช้การติดต่อกันง่ายต่อการใช้เข้าใจจัดการและทดสอบ
Doc Brown

14

ฉันรู้สึกสบายใจที่จะบอกว่าวัตถุที่เป็นของเลเยอร์สามารถพึ่งพาวัตถุจากเลเยอร์ที่ต่ำกว่าได้

พูดตามตรงฉันไม่คิดว่าคุณน่าจะสบายใจ เมื่อจัดการกับอะไรก็ตามนอกจากระบบที่ไม่สำคัญฉันจะมุ่งมั่นเพื่อให้แน่ใจว่าเลเยอร์ทั้งหมดนั้นขึ้นอยู่กับ abstractions จากเลเยอร์อื่นเท่านั้น ทั้งต่ำและสูง

ดังนั้นสำหรับตัวอย่างเช่นไม่ควรขึ้นอยู่กับObj 1 Obj 3ควรมีการพึ่งพาเช่นIObj 3และควรได้รับการบอกกล่าวว่าการดำเนินการของสิ่งที่เป็นนามธรรมนั้นคือการทำงานกับที่รันไทม์ สิ่งที่ใช้ในการเล่าเรื่องไม่ควรเกี่ยวข้องกับระดับใด ๆ เนื่องจากเป็นหน้าที่ของการทำแผนที่การพึ่งพาเหล่านั้น นั่นอาจเป็นคอนเทนเนอร์ IoC รหัสที่กำหนดเองที่เรียกว่าเช่นmainนั้นใช้บริสุทธิ์ DI หรือเพียงแค่กดปุ่มก็อาจเป็นบริการระบุตำแหน่งได้ โดยไม่คำนึงถึงการพึ่งพาไม่มีอยู่ระหว่างเลเยอร์จนกว่าสิ่งนั้นจะให้การแมป

แต่ฉันไม่แน่ใจว่าจะคิดอย่างไรเกี่ยวกับวัตถุที่ขึ้นอยู่กับวัตถุอื่นของเลเยอร์เดียวกัน

ฉันขอยืนยันว่านี่เป็นครั้งเดียวที่คุณควรมีการพึ่งพาโดยตรง เป็นส่วนหนึ่งของการทำงานภายในของเลเยอร์นั้นและสามารถเปลี่ยนแปลงได้โดยไม่กระทบกับเลเยอร์อื่น ดังนั้นจึงไม่ใช่ข้อต่อที่เป็นอันตราย


ขอบคุณสำหรับคำตอบ. ใช่เลเยอร์ไม่ควรแสดงวัตถุ แต่อินเทอร์เฟซฉันรู้ว่า แต่ฉันทิ้งมันไว้เพื่อความเรียบง่าย
bracco23

4

ให้ดูที่นี้จริง

ป้อนคำอธิบายรูปภาพที่นี่

Obj 3ตอนนี้รู้ว่าObj 4มีอยู่ แล้วอะไรล่ะ ทำไมเราถึงสนใจ

กรมทรัพย์สินทางปัญญากล่าวว่า

"โมดูลระดับสูงไม่ควรขึ้นอยู่กับโมดูลระดับต่ำทั้งสองควรขึ้นอยู่กับนามธรรม"

ตกลง แต่ไม่ใช่วัตถุทั้งหมดที่เป็นนามธรรม?

กรมฯ ยังกล่าวอีกว่า

"Abstractions ไม่ควรขึ้นอยู่กับรายละเอียดรายละเอียดควรขึ้นอยู่กับ abstractions"

ตกลง แต่ถ้าวัตถุของฉันถูกห่อหุ้มอย่างถูกต้องไม่ได้ซ่อนรายละเอียดใด ๆ

บางคนชอบที่จะยืนยันว่าวัตถุทุกอย่างต้องการอินเทอร์เฟซคำหลัก ฉันไม่ได้เป็นหนึ่งในนั้น ฉันชอบที่จะยืนยันว่าหากคุณไม่ได้ใช้พวกเขาในตอนนี้คุณต้องวางแผนที่จะจัดการกับสิ่งที่ต้องการในภายหลัง

หากรหัสของคุณสามารถ refactor ได้อย่างสมบูรณ์ในทุกรุ่นคุณสามารถแยกอินเทอร์เฟซได้ในภายหลังหากคุณต้องการ หากคุณมีรหัสเผยแพร่ที่คุณไม่ต้องการคอมไพล์ใหม่และพบว่าคุณต้องการพูดคุยผ่านอินเทอร์เฟซคุณจะต้องมีแผน

Obj 3รู้ว่าObj 4มีอยู่ แต่ไม่Obj 3ทราบว่าObj 4เป็นรูปธรรมหรือไม่

นี่คือเหตุผลว่าทำไมมันดีมากที่ไม่แพร่กระจายไปnewทุกที่ ถ้าObj 3ไม่รู้ว่าObj 4เป็นรูปธรรมมีแนวโน้มเพราะมันไม่ได้สร้างขึ้นมาถ้าคุณแอบเข้าไปในภายหลังและกลายObj 4เป็นคลาสนามธรรมObj 3จะไม่สนใจ

หากคุณสามารถทำสิ่งนั้นObj 4ได้อย่างสมบูรณ์นามธรรมตลอด สิ่งเดียวที่ทำให้อินเทอร์เฟซระหว่างพวกเขาตั้งแต่เริ่มต้นคือคุณคือความมั่นใจว่าใครบางคนจะไม่เพิ่มรหัสที่ให้โดยไม่ตั้งใจซึ่งObj 4ตอนนี้เป็นรูปธรรม ตัวสร้างที่ได้รับการป้องกันสามารถลดความเสี่ยงนั้นได้ แต่ก็นำไปสู่คำถามอื่น:

Obj 3 และ Obj 4 อยู่ในแพ็คเกจเดียวกันหรือไม่?

วัตถุมักจะถูกจัดกลุ่มในบางวิธี (แพ็คเกจเนมสเปซและอื่น ๆ ) เมื่อจัดกลุ่มอย่างชาญฉลาดเปลี่ยนผลกระทบที่น่าจะเกิดขึ้นภายในกลุ่มมากกว่าข้ามกลุ่ม

ฉันชอบที่จะจัดกลุ่มตามคุณสมบัติ หากObj 3และObj 4อยู่ในกลุ่มและเลเยอร์เดียวกันมันไม่น่าเป็นไปได้มากที่คุณจะได้เผยแพร่รายการหนึ่งและไม่ต้องการปรับโครงสร้างใหม่ในขณะที่ต้องการเปลี่ยนเฉพาะอีกรายการหนึ่ง นั่นหมายความว่าวัตถุเหล่านี้มีโอกาสน้อยที่จะได้รับประโยชน์จากการใส่สิ่งที่เป็นนามธรรมลงก่อนที่จะมีความต้องการที่ชัดเจน

หากคุณกำลังข้ามเขตแดนของกลุ่มถึงแม้ว่าเป็นความคิดที่ดีที่จะปล่อยให้วัตถุในแต่ละด้านแตกต่างกันอย่างอิสระ

มันควรจะง่าย แต่น่าเสียดายที่ทั้ง Java และ C # ทำตัวเลือกที่โชคร้ายที่ทำให้สิ่งนี้ยุ่งยาก

ใน C # เป็นธรรมเนียมที่ต้องตั้งชื่อทุกอินเทอร์เฟซคำสำคัญด้วยIคำนำหน้า ที่บังคับให้ลูกค้ารู้ว่าพวกเขากำลังพูดคุยกับส่วนติดต่อคำหลัก นั่นยุ่งกับแผนการปรับโครงสร้าง

ใน Java มันเป็นประเพณีที่จะใช้รูปแบบการตั้งชื่อที่ดีกว่า: FooImple implements Fooอย่างไรก็ตามสิ่งนี้จะช่วยได้ในระดับซอร์สโค้ดเท่านั้นเนื่องจาก Java ได้คอมไพล์อินเทอร์เฟซคำสำคัญกับไบนารีที่แตกต่างกัน ซึ่งหมายความว่าเมื่อคุณปรับโครงสร้างFooจากไคลเอนต์ที่เป็นรูปธรรมเป็นนามธรรมที่ไม่จำเป็นต้องเปลี่ยนรหัสตัวอักษรเดียวก็ยังต้องทำการคอมไพล์ใหม่

เป็นข้อบกพร่องเหล่านี้ในภาษาเฉพาะเหล่านี้ที่ป้องกันไม่ให้ผู้คนสามารถชะลอการสรุปที่เป็นทางการจนกว่าพวกเขาจะต้องการมัน คุณไม่ได้พูดภาษาที่คุณใช้ แต่เข้าใจว่ามีบางภาษาที่ไม่มีปัญหาเหล่านี้

คุณไม่ได้พูดภาษาที่คุณใช้ดังนั้นฉันจะขอให้คุณวิเคราะห์ภาษาและสถานการณ์ของคุณอย่างรอบคอบก่อนที่คุณจะตัดสินใจว่ามันจะเป็นอินเทอร์เฟซคำหลักทุกที่

หลักการ YAGNI มีบทบาทสำคัญที่นี่ แต่ "โปรดทำให้เป็นการยากที่จะยิงตัวเองในเท้า"


0

นอกเหนือจากคำตอบข้างต้นฉันคิดว่ามันอาจช่วยให้คุณมองจากมุมมองที่แตกต่างกัน

ตัวอย่างเช่นจากมุมมองกฎการพึ่งพา DR เป็นกฎที่แนะนำโดยโรเบิร์ตซีมาร์ตินของเขาที่มีชื่อเสียงสถาปัตยกรรมสะอาด

มันบอกว่า

การอ้างอิงซอร์สโค้ดจะต้องชี้เข้าเท่านั้นไปสู่นโยบายระดับสูงกว่า

โดยนโยบายระดับสูงกว่าเขาหมายถึงabstractions ระดับที่สูงขึ้น ส่วนประกอบที่รั่วไหลในรายละเอียดการใช้งานเช่นอินเทอร์เฟซหรือคลาสนามธรรมตรงกันข้ามกับคลาสคอนกรีตหรือโครงสร้างข้อมูล

สิ่งนี้คือกฎไม่ได้ จำกัด อยู่ที่การพึ่งพาระหว่างเลเยอร์ มันชี้ให้เห็นถึงการพึ่งพาระหว่างชิ้นส่วนของรหัสโดยไม่คำนึงถึงสถานที่หรือเลเยอร์ที่พวกเขาอยู่

ดังนั้นไม่มีอะไรผิดปกติกับการพึ่งพาระหว่างองค์ประกอบของชั้นเดียวกัน อย่างไรก็ตามการพึ่งพายังคงสามารถดำเนินการในการถ่ายทอดด้วยหลักการพึ่งพาเสถียรภาพ

อีกมุมมองหนึ่งคือ SRP

Decoupling เป็นวิธีของเราที่จะทำลายการพึ่งพาที่เป็นอันตรายและถ่ายทอดด้วยวิธีปฏิบัติที่ดีที่สุดเช่นการพึ่งพาการกลับกัน (IoC) อย่างไรก็ตามองค์ประกอบเหล่านั้นที่แบ่งปันเหตุผลในการเปลี่ยนแปลงไม่ได้ให้เหตุผลในการแยกเนื่องจากองค์ประกอบที่มีเหตุผลเดียวกันในการเปลี่ยนแปลงจะเปลี่ยนแปลงในเวลาเดียวกัน (เป็นไปได้สูงมาก) และจะถูกปรับใช้ในเวลาเดียวกันด้วย หากเป็นกรณีระหว่างObj3และObj4หลังจากนั้นอีกครั้งไม่มีอะไรที่ไม่ถูกต้องโดยเนื้อแท้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.