อะไรคือข้อเสียในการใช้การฉีดพึ่งพา? [ปิด]


336

ฉันพยายามที่จะแนะนำ DI เป็นรูปแบบที่นี่ในที่ทำงานและหนึ่งในนักพัฒนานำของเราต้องการทราบ: อะไร - ถ้ามี - มีข้อเสียในการใช้รูปแบบการฉีดพึ่งพาหรือไม่

หมายเหตุฉันกำลังมองหาที่ - ถ้าเป็นไปได้ - รายการที่ละเอียดถี่ถ้วนไม่ใช่การอภิปรายเชิงอัตนัยในหัวข้อ


ชี้แจง : ฉันกำลังพูดถึงรูปแบบการพึ่งพา(ดูบทความนี้โดย Martin Fowler) ไม่ใช่กรอบที่เฉพาะเจาะจงไม่ว่าจะเป็น XML (เช่นฤดูใบไม้ผลิ) หรือตามรหัส (เช่น Guice) หรือ "ม้วนตัวเอง" .


แก้ไข : บางการอภิปรายเพิ่มเติม / คุยโว / อภิปรายเกิดขึ้น/ r / การเขียนโปรแกรมที่นี่


อาจเป็นความคิดที่ดีที่จะระบุว่าเราควรจะพูดคุยกับ DI หรือเครื่องมือประเภทเฉพาะที่สนับสนุน (อิงตาม XML หรือไม่)
Jesse Millikan

5
ความแตกต่างคือฉันไม่ได้มองหาคำตอบที่ใช้กับกรอบงานเฉพาะเช่น "XML sucks" เท่านั้น :) ฉันกำลังมองหาคำตอบที่นำไปใช้กับแนวคิดของ DI ตามที่ Fowler ระบุไว้ที่นี่: martinfowler.com/articles/inject.html
Epaga

3
ฉันไม่เห็นข้อเสียทั้งหมดเลย DI (Constructor, Setter หรือ Method) มันแยกและทำให้ง่ายขึ้นโดยไม่มีค่าใช้จ่าย
Kissaki

2
@ kissaki แยกจาก setter inject stuff ดีที่สุดที่จะทำให้วัตถุที่ใช้งานได้ในการก่อสร้าง หากคุณไม่เชื่อฉันลองเพิ่มผู้ทำงานร่วมกันคนอื่นไปยังวัตถุด้วยการฉีด 'setter' คุณจะได้รับ NPE แน่นอน ....
time4tea

คำตอบ:


209

คะแนนสองสาม:

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

โดยทั่วไปประโยชน์ของการแยกชิ้นงานทำให้แต่ละงานง่ายขึ้นในการอ่านและทำความเข้าใจ แต่เพิ่มความซับซ้อนของการเตรียมงานที่ซับซ้อนมากขึ้น


72
- การแยกชั้นเรียนลดความซับซ้อน คลาสจำนวนมากไม่สร้างแอปพลิเคชันที่ซับซ้อน - คุณควรมีการพึ่งพากรอบ DI ของคุณที่ application-root
Robert

91
เราเป็นมนุษย์ หน่วยความจำระยะสั้นของเรามี จำกัด และไม่สามารถจัดการ <xxx> จำนวนมากพร้อมกันได้ มันเหมือนกันกับคลาสที่ใช้สำหรับเมธอดฟังก์ชันไฟล์หรือโครงสร้างใด ๆ ที่คุณใช้ในการพัฒนาโปรแกรมของคุณ
Håvard S

45
@Havard S: ใช่ แต่ 5 คลาสที่ซับซ้อนจริงๆนั้นไม่ง่ายกว่า 15 คลาสธรรมดา วิธีการลดความซับซ้อนคือการลดชุดการทำงานที่โปรแกรมเมอร์ต้องการโดยใช้โค้ด - คลาสที่ซับซ้อนและพึ่งพาซึ่งกันและกัน
kyoryu

35
@kyoryu ฉันคิดว่าเราทุกคนเห็นด้วยกับเรื่องนี้ โปรดทราบว่าความซับซ้อนไม่เหมือนการแต่งงานกัน การลดการแต่งงานอาจเพิ่มความซับซ้อน ฉันไม่ได้พูดว่า DI เป็นสิ่งที่ไม่ดีเพราะมันเพิ่มจำนวนชั้นเรียนฉันเน้นข้อเสียที่อาจเกิดขึ้นที่เกี่ยวข้องกับมัน :)
Håvard S

96
+1 สำหรับ "DI เพิ่มความซับซ้อน" นั่นเป็นจริงใน DI และเกิน (เกือบ) ทุกครั้งที่เราเพิ่มความยืดหยุ่นเราจะเพิ่มความซับซ้อน มันคือทั้งหมดที่เกี่ยวกับความสมดุลซึ่งเริ่มต้นด้วยการรู้ Upsides และ Downside เมื่อมีคนพูดว่า 'ไม่มีข้อเสีย' มันเป็นตัวบ่งชี้ที่แน่นอนว่าพวกเขายังไม่เข้าใจสิ่งนั้นอย่างเต็มที่
Don Branson

183

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

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

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

ลิงค์ที่เกี่ยวข้อง

http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx

http://www.joelonsoftware.com/articles/fog0000000018.html


อาจเป็นรูปแบบที่ง่ายที่สุดของการฉีดพึ่งพา (อย่าหัวเราะ) เป็นพารามิเตอร์ รหัสที่ต้องพึ่งพานั้นขึ้นอยู่กับข้อมูลและข้อมูลนั้นถูกฉีดเข้าด้วยวิธีการส่งผ่านพารามิเตอร์

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

ให้ใช้ฟังก์ชั่นดั้งเดิมที่เรียบง่าย - ไวยากรณ์ C ++ ไม่ได้มีความหมายที่นี่

void Say_Hello_World ()
{
  std::cout << "Hello World" << std::endl;
}

ฉันมีการพึ่งพาที่ฉันต้องการแยกออกและฉีด - ข้อความ "Hello World" ง่ายพอ ...

void Say_Something (const char *p_text)
{
  std::cout << p_text << std::endl;
}

มีความยืดหยุ่นมากกว่าเดิมอย่างไร? ถ้าฉันตัดสินใจว่าเอาท์พุทควรเป็น Unicode ฉันอาจต้องการเปลี่ยนจาก std :: cout เป็น std :: wcout แต่นั่นหมายความว่าสายของฉันจะต้องเป็น wchar_t ไม่ใช่ของ char ไม่ว่าผู้โทรทุกคนจะต้องเปลี่ยนหรือ (มีเหตุผลมากกว่า) การใช้งานแบบเก่าจะถูกแทนที่ด้วยอะแดปเตอร์ที่แปลสตริงและเรียกการใช้งานใหม่

นั่นคืองานบำรุงรักษาที่นั่นซึ่งไม่จำเป็นหากเราเก็บต้นฉบับไว้

และถ้ามันดูไม่สำคัญลองดูที่ฟังก์ชั่นโลกแห่งความจริงจาก Win32 API ...

http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx

นั่นคือ 12 "การพึ่งพา" เพื่อจัดการกับ ตัวอย่างเช่นหากความละเอียดหน้าจอมีขนาดใหญ่มากเราอาจต้องใช้ค่าประสาน 64- บิตและ CreateWindowEx รุ่นอื่น และใช่แล้วยังมีเวอร์ชั่นเก่าที่ยังคงห้อยอยู่ซึ่งน่าจะถูกแมปกับเวอร์ชั่นใหม่กว่าเบื้องหลัง ...

http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx

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

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

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


3
การฉีดพึ่งพาไม่มีข้อเสียใด ๆ มันจะเปลี่ยนวิธีการผ่านของคุณขึ้นกับวัตถุซึ่งไม่ได้เพิ่มความซับซ้อนหรือความยืดหยุ่น ค่อนข้างตรงกันข้าม
Kissaki

24
@Kissaki - ใช่มันเปลี่ยนวิธีที่คุณผ่านการอ้างอิงของคุณ และคุณต้องเขียนโค้ดเพื่อจัดการการส่งผ่านของการพึ่งพา และก่อนที่จะทำเช่นนั้นคุณต้องหาว่าการพึ่งพาที่จะผ่านกำหนดพวกเขาในลักษณะที่เหมาะสมกับคนที่ไม่ได้รหัสรหัสที่ขึ้นต่อกัน ฯลฯ คุณสามารถหลีกเลี่ยงผลกระทบในเวลาทำงาน (เช่นการใช้พารามิเตอร์นโยบายเพื่อแม่แบบ ใน C ++) แต่ยังคงเป็นรหัสที่คุณต้องเขียนและบำรุงรักษา หากเป็นธรรมมันเป็นราคาที่เล็กมากสำหรับรางวัลใหญ่ แต่ถ้าคุณแกล้งไม่มีราคาที่จะจ่ายนั่นก็หมายความว่าคุณจะต้องจ่ายราคานั้นเมื่อไม่มีกำไร
Steve314

6
@Kissaki - สำหรับความยืดหยุ่นเมื่อคุณระบุว่าการพึ่งพาของคุณคืออะไรคุณจะถูกล็อคเข้าที่ - คนอื่น ๆ ได้เขียนอ้างอิงเพื่อฉีดตามสเป็คนั้น หากคุณต้องการการติดตั้งใหม่สำหรับโค้ดที่ต้องพึ่งพาซึ่งแตกต่างกันเล็กน้อย - ยากคุณจะถูกล็อคเวลาที่จะเริ่มเขียนอะแดปเตอร์บางตัวสำหรับการพึ่งพาเหล่านั้นแทน (และค่าใช้จ่ายเพิ่มขึ้นเล็กน้อยและอีกชั้นหนึ่งของนามธรรม)
Steve314

ฉันไม่แน่ใจว่าฉันเข้าใจตัวอย่างนี้หากคุณพิจารณารับน้ำหนักมากเกินไป ในการแสดงผลตัวอักษร "Hello World" เราใช้ลายเซ็น () ในการส่งออกสตริง 8 บิตให้ใช้ลายเซ็น (char) หากต้องการเอาต์พุต unicode โอเวอร์โหลด (wchar_t) เห็นได้ชัดว่าในกรณีนี้ (wchar_t) เป็นสิ่งที่คนอื่นโทรหาเบื้องหลัง จำเป็นต้องมีการเขียนรหัสใหม่มาก ฉันพลาดอะไรไปรึเปล่า?
ingredients_15939

2
@ ingredients_15939 - ใช่นี่คือตัวอย่างของเล่นที่เรียบง่าย หากคุณทำสิ่งนี้จริงๆคุณเพียงแค่ใช้การโหลดมากเกินไปแทนที่จะใช้อะแดปเตอร์เนื่องจากค่าใช้จ่ายในการทำซ้ำรหัสนั้นน้อยกว่าค่าใช้จ่ายของอะแดปเตอร์ แต่โปรดทราบว่ารหัสที่ซ้ำกันนั้นเป็นสิ่งที่ไม่ดีและการใช้อะแดปเตอร์เพื่อหลีกเลี่ยงรหัสที่ซ้ำกันเป็นเทคนิคที่ดีอีกวิธีหนึ่ง (ซึ่งบางครั้งสามารถใช้งานได้มากเกินไปและผิดที่)
Steve314

77

นี่คือปฏิกิริยาเริ่มต้นของฉัน: โดยทั่วไปแล้วข้อเสียของรูปแบบใด ๆ

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

2
ทำไมต้องใช้เวลาในการเรียนรู้? ฉันคิดว่ามันทำให้สิ่งต่าง ๆ ง่ายขึ้นเมื่อเทียบกับ ejb
fastcodejava

8
สิ่งนี้ดูเป็นคลื่นเมื่อพิจารณาว่าคุณไม่ต้องการสนทนาแบบส่วนตัว ฉันขอแนะนำการสร้าง (โดยรวมหากจำเป็น) ตัวอย่างที่เป็นจริงสำหรับการตรวจสอบ การสร้างตัวอย่างที่ไม่มี DI จะเป็นจุดเริ่มต้นที่ดี จากนั้นเราสามารถท้าทายมันเพื่อแก้ไขความต้องการและตรวจสอบผลกระทบ (นี่เป็นวิธีที่สะดวกสบายอย่างยิ่งสำหรับฉันที่จะแนะนำโดยวิธีการตามที่ฉันกำลังจะไปนอน.)
Jesse Millikan

4
สิ่งนี้ต้องการตัวอย่างบางอย่างในการสำรองข้อมูลและการสอนคนหลายสิบคนดิฉันสามารถบอกคุณได้ว่ามันเป็นแนวคิดที่ง่ายมาก ๆ ในการเรียนรู้และเริ่มฝึกฝน
Chillillom

4
ฉันไม่คิดว่ารูปแบบ DI จริงๆ มัน (ควบคู่ไปกับ IoC) เป็นรูปแบบการเขียนโปรแกรมมากขึ้น - ถ้าคุณทำตามอย่างเต็มที่รหัสของคุณจะดูคล้ายนักแสดงมากกว่า OO แบบหลอกทั่วไป
kyoryu

1
+1 ฉันกำลังใช้ Symfony 2 DI อยู่เหนือรหัสผู้ใช้กำลังใช้งานอยู่
MGP

45

"ข้อเสีย" ที่ใหญ่ที่สุดของ Inversion of Control (ไม่ใช่ DI แต่อยู่ใกล้พอ) คือมันมีแนวโน้มที่จะลบจุดเดียวเพื่อดูภาพรวมของอัลกอริทึม นั่นเป็นสิ่งที่เกิดขึ้นเมื่อคุณถอดรหัสรหัสได้แล้ว - ความสามารถในการดูในที่เดียวคือสิ่งประดิษฐ์ของคลัปแน่น


2
แต่แน่นอนว่า "ข้อเสีย" นั้นเป็นเพราะธรรมชาติของปัญหาที่เรากำลังแก้ไขแก้ปัญหาเพื่อให้เราสามารถเปลี่ยนการใช้งานได้อย่างง่ายดายหมายความว่าไม่มีที่ให้ดูที่ใดและมีความเกี่ยวข้องอะไรที่สามารถดูได้? กรณีเดียวที่ฉันคิดว่าอยู่ในการแก้ไขข้อบกพร่องและสภาพแวดล้อมการดีบักควรจะสามารถนำไปปฏิบัติ
vickirk

3
นี่คือเหตุผลที่คำว่า "ข้อเสีย" อยู่ในเครื่องหมายอัญประกาศ :) การมีเพศสัมพันธ์ที่หลวมและการห่อหุ้มอย่างแน่นหนาทำให้ไม่สามารถมองเห็นได้ทุกที่ "โดยนิยาม ดูความคิดเห็นของฉันเกี่ยวกับคำตอบของ Havard S หากคุณรู้สึกว่าฉันไม่เห็นด้วยกับ DI / IoC
kyoryu

1
ฉันเห็นด้วย (ฉันยังโหวตให้คุณ) ฉันแค่ทำให้จุด
vickirk

1
@ vickirk: ข้อเสียที่ฉันคิดว่ามันยากสำหรับมนุษย์ที่จะเข้าใจ สิ่งที่แยกออกจากกันจะเพิ่มความซับซ้อนในแง่ที่ว่ามนุษย์เข้าใจยากและใช้เวลาในการทำความเข้าใจอย่างเต็มที่
Bjarke Freund-Hansen

2
ในทางตรงกันข้ามข้อดีอย่างหนึ่งของ DI คือคุณสามารถดู Constructor ของแต่ละคลาสและทำงานได้ทันทีว่าคลาสขึ้นอยู่กับอะไร (เช่นคลาสใดที่จำเป็นต้องใช้ในการทำงาน) นี่เป็นเรื่องยากสำหรับรหัสอื่น ๆ เนื่องจากรหัสสามารถสร้างคลาสที่จำใจได้
Contango

42

7
ฉันอยากรู้อยากเห็นเมื่อมีคนถามหาสาเหตุทำไมคำตอบในวิญญาณ "ไม่มี" upvoted "และผู้ที่มีข้อมูลบางส่วนที่เกี่ยวข้องกับคำถามไม่ได้หรือไม่
กาเบรียลŠčerbák

12
-1 เพราะฉันไม่ได้มองหาคอลเลกชันลิงก์ฉันกำลังมองหาคำตอบจริง: วิธีการสรุปคะแนนของแต่ละบทความ จากนั้นฉันก็จะลงคะแนนแทน โปรดทราบว่าบทความตัวเองค่อนข้างน่าสนใจแม้ว่ามันจะดูเหมือนว่าสองคนแรกเป็นจริงเชิงลบ debunking ของ DI?
Epaga

4
ฉันสงสัยว่าคำตอบ upvote ที่มากที่สุดนั้น downvoted เช่นกันเพราะมันไม่ได้ตอบคำถามเลย imho :) แน่นอนว่าฉันรู้ว่าสิ่งที่คุณถามและสิ่งที่ฉันตอบฉันไม่ได้ขอ upvotes ฉันแค่สับสนว่าทำไม คำตอบไม่ได้ช่วยในขณะที่พูดว่า DI ข้อเสียคือมันเจ๋งเกินไปกำลังช่วยอะไรมากมาย
Gabriel Ščerbák

41

ฉันใช้ Guice (Java DI Framework) อย่างกว้างขวางในช่วง 6 เดือนที่ผ่านมา แม้ว่าโดยรวมแล้วฉันคิดว่ามันยอดเยี่ยม (โดยเฉพาะจากมุมมองการทดสอบ) แต่ก็มีข้อเสียอยู่บ้าง สะดุดตาที่สุด:

  • รหัสสามารถเข้าใจได้ยากขึ้น การฉีดพึ่งพาสามารถใช้ใน ... สร้างสรรค์ ... วิธี ตัวอย่างเช่นฉันเพิ่งเจอรหัสบางส่วนที่ใช้คำอธิบายประกอบที่กำหนดเองเพื่อฉีด IOStreams บางอย่าง (เช่น: @ Server1Stream, @ Server2Stream) ในขณะที่ใช้งานได้และฉันจะยอมรับว่ามีความสง่างามบางอย่างมันทำให้การทำความเข้าใจ Guice การฉีดจำเป็นต้องเข้าใจรหัส
  • เส้นโค้งการเรียนรู้ที่สูงขึ้นเมื่อโครงงานเรียนรู้ สิ่งนี้เกี่ยวข้องกับประเด็นที่ 1 เพื่อที่จะเข้าใจว่าโครงการที่ใช้การฉีดแบบพึ่งพานั้นคุณต้องเข้าใจทั้งรูปแบบการฉีดแบบพึ่งพาและกรอบเฉพาะ เมื่อฉันเริ่มงานปัจจุบันของฉันฉันใช้เวลาไม่กี่ชั่วโมงที่สับสนในสิ่งที่ Guice กำลังทำอยู่เบื้องหลัง
  • ตัวสร้างมีขนาดใหญ่ แม้ว่าสิ่งนี้สามารถแก้ไขได้ส่วนใหญ่ด้วยตัวสร้างเริ่มต้นหรือโรงงาน
  • ข้อผิดพลาดสามารถทำให้งง ตัวอย่างล่าสุดของฉันนี้คือฉันมีการชนกันของชื่อธง 2 Guice กลืนข้อผิดพลาดอย่างเงียบ ๆ และหนึ่งในธงของฉันไม่ได้เริ่มต้น
  • ข้อผิดพลาดถูกผลักไปที่เวลาทำงาน ถ้าคุณกำหนดค่าโมดูล Guice ของคุณอย่างไม่ถูกต้อง (การอ้างอิงแบบวงกลม, การรวมที่ไม่ถูกต้อง, ... ) ข้อผิดพลาดส่วนใหญ่จะไม่ถูกเปิดเผยในระหว่างการคอมไพล์เวลา แต่ข้อผิดพลาดจะปรากฏเมื่อโปรแกรมทำงานจริง

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

นอกจากนี้ฉันเห็นด้วยกับโปสเตอร์อื่น ๆ ที่สามารถใช้การฉีดพึ่งพาได้มากเกินไป


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

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

@RichardTingle ฉันเข้าใจว่ามันจะไม่เหมือนกับเครือข่ายความปลอดภัยที่คอมไพเลอร์จัดหาให้ แต่ DI เป็นเครื่องมือที่ใช้อย่างถูกต้องตามที่บอกในกล่องจากนั้นข้อผิดพลาดรันไทม์จะถูก จำกัด เฉพาะการเริ่มต้นแอป จากนั้นเราสามารถดูการเริ่มต้นแอพเป็นเฟสของการคอมไพล์สำหรับโมดูล DI จากประสบการณ์ของผมส่วนใหญ่หากแอปเริ่มต้นขึ้นแล้วจะไม่มีการผูกหรือการอ้างอิงที่ไม่ถูกต้อง PS - ฉันใช้ NInject กับ C #
k4vin

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

1
ฉันจะเพิ่ม "ยากที่จะรักษารหัสให้สะอาด" ในรายการของคุณ คุณไม่มีทางรู้ว่าคุณสามารถลบการลงทะเบียนก่อนที่จะทดสอบรหัสอย่างกว้างขวางโดยไม่ได้
fernacolo

24

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

รหัสที่ DI ใช้บ่อยๆอาจเป็นรหัส Ravioliซึ่งแต่ละชั้นเรียนขนาดเล็กเป็นเหมือนนักเก็ตราวีโอลี่แต่ละคน - มันทำสิ่งเล็ก ๆ น้อย ๆ และยึดหลักความรับผิดชอบเดี่ยวซึ่งเป็นสิ่งที่ดี แต่การดูคลาสด้วยตัวเองมันยากที่จะเห็นว่าระบบโดยรวมทำอะไรเพราะสิ่งนี้ขึ้นอยู่กับว่าชิ้นส่วนเล็ก ๆ เหล่านี้เข้ากันได้ดีแค่ไหนซึ่งยากที่จะมองเห็น ดูเหมือนว่ามันเป็นกองเล็ก ๆ

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

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


1
ใช่ฉันชอบคำว่า "รหัสราวีโอลี่"; ฉันแสดงมันยาวมากเมื่อฉันพูดถึงข้อเสียของ DI ถึงกระนั้นฉันก็ยังนึกภาพไม่ออกว่าการพัฒนาเฟรมเวิร์กหรือแอพพลิเคชั่นใด ๆ ใน Java โดยไม่ใช้ DI
Howard M. Lewis Ship

13

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

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


เพื่อแสดงให้เห็นถึงจุดที่สองที่ดีกว่านี่คือข้อความที่ตัดตอนมาจากบทความนี้ ( ต้นฉบับดั้งเดิม ) ซึ่งฉันเชื่อว่าเป็นปัญหาพื้นฐานในการสร้างระบบใด ๆ ไม่ใช่แค่ระบบคอมพิวเตอร์

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

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

DI แก้ปัญหานี้ได้หรือไม่? ไม่ แต่มันจะช่วยให้คุณเห็นอย่างชัดเจนว่าคุณกำลังพยายามมอบหมายความรับผิดชอบในการออกแบบทุกห้องให้กับผู้อยู่อาศัยหรือไม่


13

สิ่งหนึ่งที่ทำให้ฉันดิ้นรนเล็กน้อยกับ DI คือข้อสันนิษฐานว่าวัตถุที่ถูกฉีดทั้งหมดมีราคาถูกในการสร้างอินสแตนซ์และไม่มีผลข้างเคียง - หรือ - การพึ่งพานั้นถูกใช้บ่อย ๆ

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

Public Class MyClass
    Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService

    Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
        Me.mExLogHandlerService = exLogHandlerService
    End Sub

     ...
End Class

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

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

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


1
ฉันเข้าใจสิ่งที่คุณพูด แต่ฉันไม่คิดว่ามันยุติธรรมที่จะพูดว่า "เมื่อคุณสร้างการใช้งานของการพึ่งพาคุณต้องออกแบบด้วย DI ในใจ" - ฉันคิดว่าคำสั่งที่แม่นยำมากขึ้นจะเป็น "DI ทำงาน ดีที่สุดเมื่อใช้กับคลาสที่นำไปใช้กับแนวทางปฏิบัติที่ดีที่สุดเกี่ยวกับค่าใช้จ่ายในการสร้างอินสแตนซ์และการขาดผลข้างเคียง กรณีที่เลวร้ายที่สุดคุณสามารถแทรกการใช้งานพร็อกซีขี้เกียจที่ทำให้การจัดสรรวัตถุจริงจนใช้งานครั้งแรก
Jolly Roger

1
คอนเทนเนอร์ IoC ที่ทันสมัยใด ๆ จะอนุญาตให้คุณระบุอายุการใช้งานของออบเจกต์สำหรับประเภท / อินเตอร์เฟสนามธรรมที่เฉพาะเจาะจง นอกจากนี้คุณยังสามารถจัดเตรียมวิธีการ / ตัวแทนจากโรงงานเพื่อยกตัวอย่างวิธีขี้เกียจโดยใช้ Func <T> หรือ Lazy <T>
Dmitry S.

จับได้เห็นชัดตรงเผง. การพึ่งพาการเพิ่มจำนวนหน่วยความจำทันทีโดยไม่จำเป็น ฉันมักจะใช้ "lazy-loading" กับ getters ที่สร้างอินสแตนซ์ของคลาสเมื่อเรียกใช้ คุณสามารถจัดทำค่าเริ่มต้นตัวสร้างโดยไม่มีพารามิเตอร์เช่นเดียวกับตัวสร้างที่ตามมาที่ยอมรับการอ้างอิงทันที ในกรณีแรกคลาสที่ใช้ IErrorLogger นั้นถูกสร้างอินสแตนซ์เฉพาะthis.errorLogger.WriteError(ex)เมื่อมีข้อผิดพลาดเกิดขึ้นในคำสั่ง try / catch
John Bonfardeci

12

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


11

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

โดยเฉพาะอย่างยิ่งถ้าคุณควบคุมคลิก / Command-Click ในการร้องขอวิธีการในรหัสมันจะนำคุณไปสู่การประกาศวิธีการในส่วนติดต่อแทนการใช้งานที่เป็นรูปธรรม

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

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

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


5
Ctrl-shift-B พร้อมตัว Resharper จะนำคุณไปสู่การปฏิบัติ
adrianm

1
แต่แล้วอีกครั้งเราจะไม่ (ในโลกอุดมคติ) มีการใช้งานอย่างน้อย 2 อย่างคือการใช้งานจริงอย่างน้อยหนึ่งการทดสอบและการจำลองสำหรับการทดสอบหน่วย ;-)
vickirk

1
ใน Eclipse หากคุณกด Ctrl ค้างไว้และวางเมาส์เหนือรหัสการเรียกใช้เมธอดมันจะแสดงเมนูเพื่อเปิด Declaration หรือ Implementation
Sam Hasler

หากคุณอยู่ที่นิยามของอินเทอร์เฟซให้เน้นชื่อวิธีการและกด Ctrl + T เพื่อแสดงลำดับชั้นของประเภทสำหรับวิธีนั้น - คุณจะเห็นผู้ดำเนินการของวิธีนั้นในโครงสร้างลำดับชั้นของประเภท
qualidafial

10

Constructor-based injection พึ่งพา (โดยไม่ต้องอาศัยความช่วยเหลือของ "กรอบ") เป็นวิธีที่สะอาดและเป็นประโยชน์ในการสร้างรหัส OO ในฐานรหัสที่ดีที่สุดที่ฉันเคยเห็นมานานหลายปีใช้เวลากับอดีตเพื่อนร่วมงานของ Martin Fowler ฉันเริ่มสังเกตเห็นว่าชั้นเรียนที่ดีที่สุดที่เขียนด้วยวิธีนี้จบลงด้วยdoSomethingวิธีการเดียว

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


1
มีปัญหากับตัวสร้างที่ใช้เป็นที่คุณจะต้องเสมอเพื่อเพิ่ม args คอนสตรัคเพิ่มเติม ...
มิเกลปิง

1
ฮ่าฮ่า หากคุณทำมากเกินไปคุณจะเห็นว่าโค้ดของคุณเร็วเกินไปและคุณจะทำการปรับแก้ใหม่ นอกจากนี้ ctrl-f6 ไม่ใช่เรื่องยาก
time4tea

และแน่นอนว่าสิ่งที่ตรงกันข้ามก็เป็นจริง: มันเป็นเพียงแค่วิธีการทำงานที่ใช้เวลายาวนานในการเขียนคลาสเพื่อปิดการใช้งานเพื่อให้ได้ประโยชน์จากการเขียนโปรแกรม OO
CurtainDog

หลายปีที่ผ่านมาฉันสร้างระบบวัตถุโดยใช้การปิดใน Perl ดังนั้นฉันจึงได้สิ่งที่คุณพูด แต่การห่อหุ้มข้อมูลไม่ได้เป็นประโยชน์เฉพาะของการเขียนโปรแกรม OO ดังนั้นจึงไม่ชัดเจนว่าคุณลักษณะที่เป็นประโยชน์เหล่านี้ของ OO จะเปรียบเทียบได้อย่างไร kludgy และ long-hand ที่จะได้รับในภาษาที่ใช้งานได้
sanityinc

9

ฉันพบว่าการฉีดคอนสตรัคเตอร์สามารถนำไปสู่การสร้างที่น่าเกลียดขนาดใหญ่ (และฉันใช้มันตลอดโค๊ดเบสของฉัน - บางทีวัตถุของฉันมันละเอียดเกินไป?) นอกจากนี้บางครั้งการฉีดคอนสตรัคฉันก็จบลงด้วยการพึ่งพาแบบวงกลมที่น่ากลัว (แม้ว่าจะหายากมาก) ดังนั้นคุณอาจพบว่าตัวเองต้องมีวงจรชีวิตของรัฐพร้อมบางชนิดด้วยการฉีดพึ่งพาหลายรอบในระบบที่ซับซ้อนมากขึ้น

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

(ในฐานะ sidenote ฉันพบว่าหัวข้อทั้งหมดค่อนข้าง "ทางศาสนา" แต่ระยะของคุณจะแตกต่างกันไปตามระดับของความกระตือรือร้นด้านเทคนิคในทีมนักพัฒนาของคุณ!)


8
หากคุณมีคอนสตรัคเตอร์ที่น่าเกลียดขนาดใหญ่ชั้นเรียนของคุณอาจใหญ่และคุณต้องพึ่งพามาก?
Robert

4
เป็นไปได้อย่างแน่นอนว่าฉันยินดีที่จะให้ความบันเทิง! ... น่าเศร้าที่ฉันไม่มีทีมงานที่สามารถแสดงความคิดเห็นกับเพื่อนได้ ไวโอลินเล่นเบา ๆ ในพื้นหลังและจากนั้นจางหายหน้าจอเป็นสีดำ ...
เจมส์ B

1
ดังที่มาร์คเซมานเศร้าเหนือ "มันอาจเป็นอันตรายต่ออาชีพการงานของคุณ" ...
Robert

ฉันไม่มีการเล่าเรื่องพื้นหลังเบาะแสสามารถแสดงออกได้ที่นี่: P
Anurag

@ Robert ฉันกำลังพยายามหาคำพูดที่เขากล่าวว่าข้างต้นที่ไหน
เหลียง

8

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

เช่นเดียวกับคำตอบของ Mark Seemann บรรทัดล่างคือคุณใช้เวลาในการเป็นนักพัฒนาซอฟต์แวร์ที่ดีกว่าการแฮ็ครหัสบิตด้วยกัน สิ่งที่ธุรกิจของคุณจะค่อนข้างมี? มีเพียงคุณเท่านั้นที่ตอบได้


จุดดี. นั่นคือคุณภาพไม่ดี / จัดส่งที่รวดเร็วเทียบกับคุณภาพที่ดี / จัดส่งช้า ข้อเสียคืออะไร? DI ไม่ใช่เวทมนต์คาดว่ามันจะเป็นข้อเสีย
เหลียง

5

DI เป็นเทคนิคหรือรูปแบบและไม่เกี่ยวข้องกับกรอบใด ๆ คุณสามารถวางสายการอ้างอิงของคุณได้ด้วยตนเอง DI ช่วยคุณด้วย SR (ความรับผิดชอบเดี่ยว) และ SoC (แยกความกังวล) DI นำไปสู่การออกแบบที่ดีขึ้น จากมุมมองของฉันและประสบการณ์ที่ไม่มีข้อเสีย เช่นเดียวกับรูปแบบอื่น ๆ คุณสามารถเข้าใจผิดหรือใช้ผิดวิธี (แต่สิ่งที่เป็นในกรณีของ DI ค่อนข้างยาก)

หากคุณแนะนำ DI เป็นหลักการสำหรับแอปพลิเคชันรุ่นเก่าโดยใช้กรอบงาน - ความผิดพลาดที่ใหญ่ที่สุดเพียงข้อเดียวที่คุณสามารถทำได้คือการใช้งานผิดประเภทในฐานะ Service-Locater DI + Framework นั้นยอดเยี่ยมและทำให้ทุกอย่างดีขึ้นทุกที่ที่ฉันเห็น! จากมุมมองขององค์กรมีปัญหาทั่วไปเกี่ยวกับกระบวนการเทคนิครูปแบบใหม่ ... :

  • คุณต้องฝึกทีมคุณ
  • คุณต้องเปลี่ยนใบสมัครของคุณ (ซึ่งรวมถึงความเสี่ยง)

โดยทั่วไปคุณต้องลงทุนเวลาและเงินนอกจากนั้นไม่มีข้อเสียจริงๆ!


3

อ่านรหัสได้ คุณจะไม่สามารถเข้าใจโฟลว์โค้ดได้ง่ายเนื่องจากการอ้างอิงถูกซ่อนอยู่ในไฟล์ XML


9
คุณไม่จำเป็นต้องใช้ไฟล์การกำหนดค่า XML สำหรับการฉีดพึ่งพา - เลือกคอนเทนเนอร์ DI ซึ่งรองรับการกำหนดค่าในรหัส
Håvard S

8
การฉีดพึ่งพาไม่ได้แปลว่าไฟล์ XML ดูเหมือนว่านี่อาจเป็นกรณีใน Java แต่ใน. NET เราละทิ้งการมีเพศสัมพันธ์เมื่อหลายปีก่อน
Mark Seemann

6
หรืออย่าใช้ภาชนะ DI เลย
Jesse Millikan

หากคุณรู้ว่ารหัสกำลังใช้ DI คุณสามารถสันนิษฐานได้ว่าใครเป็นผู้ตั้งค่าการอ้างอิง
Bozho

ใน Java Guice ของ Google ไม่ต้องการไฟล์ XML เช่น
Epaga

2

สองสิ่ง:

  • พวกเขาต้องการการสนับสนุนเครื่องมือพิเศษเพื่อตรวจสอบว่าการกำหนดค่านั้นถูกต้อง

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

นี่คือเหตุผลหนึ่งว่าทำไมรูปแบบ 'เค้ก' (ตามที่รู้จักกันในชุมชน Scala) เป็นแนวคิดที่ดี: การเดินสายระหว่างส่วนประกอบต่างๆสามารถตรวจสอบได้โดยตัวตรวจสอบชนิด คุณไม่มีประโยชน์กับการทำหมายเหตุประกอบหรือ XML

  • มันทำให้การวิเคราะห์แบบคงที่ทั่วโลกของโปรแกรมยากมาก

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


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

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

อา. ในกรณีนี้ฉันถอนความรำคาญออกมาอย่างมีความสุข ขอโทษ.
time4tea

2

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


1

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


3
เพียงเพื่อให้ตัวเลขภาชนะ DI ควรแก้ไขหลายพันอ้างอิงต่อวินาที ( codinginstinct.com/2008/05/… ) คอนเทนเนอร์ DI อนุญาตให้มีการสร้างอินสแตนซ์ที่เลื่อนออกไป ประสิทธิภาพควร (แม้ในแอปพลิเคชันขนาดใหญ่) ไม่เป็นปัญหา หรือปัญหาประสิทธิภาพการทำงานอย่างน้อยควรกำหนดแอดเดรสได้และไม่ใช่เหตุผลในการตัดสินใจกับ IoC และกรอบงาน
Robert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.