อะไรคือ“ วิธีที่ถูกต้อง” ในการใช้ DI ใน. NET


22

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

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

มันจะเป็นวิธีที่ถูกต้องในการใช้งานการฉีดพึ่งพาในใบสมัครของฉันหรือฉันควรจะใช้มันตามหลักการอื่น ๆ ?


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

เป็นการยากที่จะตอบโดยไม่ทราบว่าคุณกำลังสร้างโครงการ. net คำตอบที่ดีสำหรับ WPF อาจเป็นคำตอบที่ไม่ดีสำหรับ MVC เช่น
JMK

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

คำตอบ:


30

อย่าคิดเกี่ยวกับเครื่องมือที่คุณจะใช้ คุณสามารถทำ DI โดยไม่มีคอนเทนเนอร์ IoC

จุดแรก: Mark Seemann มีหนังสือที่ดีมากเกี่ยวกับ DI ใน. Net

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

ประการที่สาม: การฉีดคอนสตรัคเตอร์เป็นวิธีที่น่าจะเป็นไปได้มากที่สุด (มีหลายกรณีที่คุณไม่ต้องการมัน แต่ไม่มากนัก)

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


5
คำแนะนำที่ยอดเยี่ยมทั้งหมด; โดยเฉพาะอย่างยิ่งในส่วนแรก: เรียนรู้วิธีการทำ DI ที่บริสุทธิ์และจากนั้นเริ่มดูที่คอนเทนเนอร์ IoC ที่อาจลดจำนวนรหัสต้นแบบที่ต้องการโดยวิธีการนั้น
David Arno

6
... หรือข้าม IoC คอนเทนเนอร์ทั้งหมดเข้าด้วยกัน - เพื่อรักษาประโยชน์ทั้งหมดของการตรวจสอบแบบคงที่
Den

ฉันชอบคำแนะนำนี้เป็นจุดเริ่มต้นที่ดีก่อนเข้า DI และจริง ๆ แล้วฉันมีหนังสือ Mark Seemann
นูป

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

1
ระวัง. การใช้แลมบ์ดาฉีดอาจทำให้เกิดความบ้าคลั่งอย่างรวดเร็วโดยเฉพาะอย่างยิ่งความเสียหายที่เกิดจากการออกแบบที่ทดสอบ ฉันรู้ว่า. ฉันลงไปที่เส้นทางนั้น
jpmc26

13

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

ส่วนแรกตอบโดย @Miyamoto Akira เป็นอย่างดี (โดยเฉพาะคำแนะนำในการอ่านหนังสือ "พึ่งพาการฉีดใน. net" ของ Mark Seemann บล็อก Marks ยังเป็นแหล่งข้อมูลฟรีที่ดี

ส่วนที่สองนั้นซับซ้อนกว่ามาก

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

นี่จะเน้นการละเมิด SRP ทั้งหมดที่คุณทำดังนั้นคุณสามารถเริ่มแบ่งชั้นเรียนเป็นผู้ทำงานร่วมกันที่เล็กลง

ปัญหาต่อไปที่คุณจะพบคือคลาสที่ขึ้นอยู่กับพารามิเตอร์รันไทม์สำหรับการก่อสร้าง คุณสามารถแก้ไขได้โดยการสร้างโรงงานแบบง่าย ๆ ด้วยการFunc<param,type>เริ่มต้นในตัวสร้างและเรียกพวกเขาในวิธีการ

ขั้นตอนต่อไปคือการสร้างส่วนต่อประสานสำหรับการพึ่งพาของคุณและเพิ่มตัวสร้างที่สองให้กับคลาสของคุณที่ยกเว้นส่วนต่อประสานเหล่านี้ ตัวสร้างแบบไม่มีพารามิเตอร์ของคุณจะสร้างอินสแตนซ์ที่เป็นรูปธรรมขึ้นมาใหม่และส่งต่อไปยังตัวสร้างใหม่ โดยทั่วไปเรียกว่า 'B * stard Injection' หรือ 'Poor mans DI'

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

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

สิ่งนี้จะทำให้เกิดกรณีของพารามิเตอร์ตัวสร้างรันไทม์เพิ่มขึ้นเพื่อจัดการกับเมื่อก่อน

เมื่อดำเนินการเสร็จแล้วคุณสามารถเริ่มต้นการลบ constructor ที่ไม่มีพารามิเตอร์และ refactor ไปที่ pure DI

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


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

1
ดีใจที่ฉันสามารถช่วยได้และใช่ฉันยอมรับว่าข้อได้เปรียบที่ใหญ่ที่สุดของ DI คือข้อต่อหลวมและความสามารถในการกำหนดค่าใหม่ได้อย่างง่ายดายด้วยการทดสอบหน่วยเป็นผลข้างเคียงที่ดี
Steve

1

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

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

วิธีที่ง่ายที่สุดในการระบุเป้าหมายของคุณสำหรับ DI refactor คือคุณต้องการลบอินสแตนซ์ทั้งหมดของโอเปอเรเตอร์ 'ใหม่' ออกจากส่วนนี้ โดยทั่วไปแล้วแบ่งออกเป็นสองประเภท:

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

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

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

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

'เพียงแค่' ทำซ้ำข้างต้นสำหรับแต่ละองค์ประกอบของแอปพลิเคชันของคุณย้ายการอ้างอิงไปยังคอนเทนเนอร์ IoC ขึ้นไปจนกว่าคุณจะต้องการเพียงความรู้เกี่ยวกับมันเท่านั้น


1
คำแนะนำที่ดี: เริ่มจากองค์ประกอบเล็ก ๆ มากกว่า 'BIG re-write'
Daniel Hollinrake

0

วิธีการที่ถูกต้องคือการใช้ตัวสร้างการฉีดถ้าคุณใช้

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

แล้วคุณจะจบลงด้วยบริการที่ตั้งกว่าการฉีดพึ่งพา


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

2
ไม่เมื่อคุณเริ่มต้นคอนเทนเนอร์ DI คุณต้องระบุการนำไปปฏิบัติของอินเตอร์เฟสและคอนเทนเนอร์ DI จะสร้างอินสแตนซ์และฉีดไปยังตัวสร้าง
นกกระทุงบินต่ำ

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

2
หากบริการที่แตกต่างกัน 10 รายการเกิดขึ้นเพราะมีบางคนละเมิด SRP ซึ่งควรแบ่งออกเป็นส่วนประกอบที่เล็กกว่า
นกกระทุงบินต่ำ

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

0

คุณบอกว่าคุณต้องการใช้ แต่ไม่ระบุสาเหตุ

DI ไม่ได้เป็นอะไรมากไปกว่าการจัดหากลไกสำหรับสร้าง concretions จากอินเตอร์เฟส

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

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

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


0

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

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

การแปลงแอปพลิเคชั่นที่มีอยู่ให้กับ DI ทั้งหมดเป็นขั้นตอนใหญ่ แต่การแยกปัญหาที่ชัดเจนในการทำเช่นนั้นคุณจะต้อง (เพื่อทำให้ชีวิตของคุณง่ายขึ้น) เพื่อสำรวจเครื่องมือ DI ที่จะทำการผูกเป็นกลุ่มโดยอัตโนมัติ (หลักสำคัญของสิ่งที่คล้ายกับ Ninject คือการ"kernel.Bind<someInterface>().To<someConcreteClass>()"เรียกที่คุณทำเพื่อให้ตรงกับการประกาศส่วนต่อประสานกับคลาสที่เป็นรูปธรรมที่คุณต้องการใช้เพื่อใช้อินเทอร์เฟซเหล่านั้นมันคือการเรียก "Bind" ที่อนุญาตให้ gadget ของคุณ อินสแตนซ์ของวัตถุที่จำเป็นต้องพึ่งพาตัวสร้างทั่วไป (รหัสหลอกที่แสดงที่นี่) สำหรับบางคลาสอาจเป็น:

public class SomeClass
{
  private ISomeClassA _ClassA;
  private ISomeOtherClassB _ClassB;

  public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
  {
    if (aInstanceOfA == null)
      throw new NullArgumentException();
    if (aInstanceOfB == null)
      throw new NullArgumentException();
    _ClassA = aInstanceOfA;
    _ClassB = aInstanceOfB;
  }

  public void DoSomething()
  {
    _ClassA.PerformSomeAction();
    _ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
  }
}

โปรดทราบว่าไม่มีรหัสใดในรหัสที่สร้าง / จัดการ / นำออกใช้ทั้งอินสแตนซ์ของ SomeConcreteClassA หรือของ SomeOtherConcreteClassB ตามความเป็นจริงแล้วไม่มีการอ้างอิงชั้นรูปธรรมเลยแม้แต่น้อย ดังนั้น ... เวทมนตร์เกิดขึ้นที่ไหน?

ในส่วนเริ่มต้นของแอพของคุณสิ่งต่อไปนี้เกิดขึ้น (อีกครั้งนี่คือรหัสหลอก แต่มันค่อนข้างใกล้เคียงกับของจริง (Ninject) ... ):

public void StartUp()
{
  kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
  kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}

โค้ดที่นิดหน่อยนั้นบอกให้ Gadget ของ Ninject ค้นหาตัวสร้างสแกนหาอินสแตนซ์ของอินเทอร์เฟซที่ได้รับการกำหนดค่าให้จัดการ (นั่นคือการเรียก "Bind") จากนั้นสร้างและแทนที่อินสแตนซ์ของคลาสคอนกรีต มีการอ้างอิงอินสแตนซ์

มีเครื่องมือที่ดีที่เติมเต็ม Ninject ที่เรียกว่า Ninject.Extensions.Conventions (ยังเป็นแพ็คเกจ NuGet อื่น) ที่จะทำงานนี้ให้คุณเป็นกลุ่ม ไม่ให้ห่างจากประสบการณ์การเรียนรู้ที่ยอดเยี่ยมที่คุณจะทำเมื่อคุณสร้างมันขึ้นมาด้วยตัวคุณเอง แต่เพื่อเริ่มต้นด้วยตัวคุณเองนี่อาจเป็นเครื่องมือในการตรวจสอบ

หากหน่วยความจำรองรับ Unity (จาก Microsoft อย่างเป็นทางการในขณะนี้เป็นโครงการโอเพ่นซอร์ส) มีการเรียกเมธอดหรือสองวิธีที่ทำสิ่งเดียวกันเครื่องมืออื่นมีตัวช่วยที่คล้ายกัน

ไม่ว่าเส้นทางไหนที่คุณเลือกอ่านหนังสือของ Mark Seemann สำหรับการฝึกอบรม DI ของคุณอย่างแน่นอนอย่างไรก็ตามมันควรจะชี้ให้เห็นว่าแม้แต่ "Great Ones" ของโลกวิศวกรรมซอฟต์แวร์ (เช่น Mark) สามารถสร้างข้อผิดพลาดที่ชัดเจน - Mark ลืมทั้งหมด Ninject ในหนังสือของเขาดังนั้นนี่คือแหล่งข้อมูลอื่นที่เขียนขึ้นเพื่อ Ninject ฉันมีมันและอ่านที่ดี: การเรียนรู้การฉีดเพื่อการพึ่งพา


0

ไม่มี "วิธีที่ถูกต้อง" แต่มีหลักการง่ายๆสองสามข้อที่จะปฏิบัติตาม:

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

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


ดังนั้นวิธีการสร้างวัตถุในช่วงรันไทม์โดยไม่มี "ใหม่" และไม่ทราบว่าภาชนะ DI?

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

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