สิ่งนี้มีจุดมุ่งหมายเพื่อเป็นคำตอบที่สมบูรณ์สำหรับ Doc Brown และเพื่อตอบสนองต่อความคิดเห็นที่ยังไม่ได้คำตอบของ Dinaiz ที่ยังคงเกี่ยวข้องกับคำถาม
สิ่งที่คุณอาจต้องมีคือกรอบการทำงานสำหรับ DI การมีลำดับชั้นที่ซับซ้อนนั้นไม่ได้หมายความว่าการออกแบบไม่ดี แต่ถ้าคุณต้องฉีด TimeFactory จากล่างขึ้นบน (จาก A ถึง D) แทนที่จะฉีดลงไปที่ D โดยตรงอาจเป็นไปได้ว่ามีบางอย่างผิดปกติ
เดี่ยว ไม่เป็นไรขอบคุณ. หากคุณต้องการเพียง istance เพียงตัวเดียวให้แบ่งใช้กับบริบทแอปพลิเคชันของคุณ (การใช้คอนเทนเนอร์ IoC สำหรับ DI เช่น Infector ++ ต้องการเพียงแค่ผูก TimeFactory เป็น istance เดียว) นี่คือตัวอย่าง (C ++ 11 ตามวิธี แต่อาจเป็น C ++ ถึง C ++ 11 แล้วหรือยังคุณได้รับแอปพลิเคชันแบบไม่รั่วไหลฟรี):
Infector::Container ioc; //your app's context
ioc.bindSingleAsNothing<TimeFactory>(); //declare TimeFactory to be shared
ioc.wire<TimeFactory>(); //wire its constructor
// if you want to be sure TimeFactory is created at startup just request it
// (else it will be created lazily only when needed)
auto myTimeFactory = ioc.buildSingle<TimeFactory>();
ตอนนี้จุดดีของคอนเทนเนอร์ IoC คือคุณไม่จำเป็นต้องผ่านโรงงานเวลาถึง D ถ้าคลาส "D" ของคุณต้องการโรงงานเวลาเพียงแค่ใส่โรงงานเวลาเป็นพารามิเตอร์คอนสตรัคเตอร์สำหรับคลาส D
ioc.bindAsNothing<A>(); //declare class A
ioc.bindAsNothing<B>(); //declare class B
ioc.bindAsNothing<D>(); //declare class D
//constructors setup
ioc.wire<D, TimeFactory>(); //time factory injected to class D
ioc.wire<B, D>(); //class D injected to class B
ioc.wire<A, B>(); //class B injected to class A
ตามที่คุณเห็นคุณฉีด TimeFactory เพียงครั้งเดียว วิธีใช้ "A" ง่ายมากทุกคลาสจะถูกฉีดสร้างขึ้นในโรงงานหลักหรือเป็นโรงงาน
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
ทุกครั้งที่คุณสร้างคลาส A มันจะถูกฉีดโดยอัตโนมัติ (สันหลังยาวขี้เกียจ) ที่มีการพึ่งพาทั้งหมดจนถึง D และ D จะถูกฉีดด้วย TimeFactory ดังนั้นโดยการเรียกใช้เพียง 1 วิธีเท่านั้นที่คุณมีลำดับชั้นที่สมบูรณ์ของคุณ (และแม้กระทั่งลำดับชั้นที่ซับซ้อน การลบรหัสแผ่นบอยเลอร์จำนวนมาก): คุณไม่ต้องเรียก "ใหม่ / ลบ" และนั่นสำคัญมากเพราะคุณสามารถแยกตรรกะการใช้งานออกจากรหัสกาวได้
D สามารถสร้างวัตถุเวลาด้วยข้อมูลที่มีเพียง D
นั่นเป็นเรื่องง่าย TimeFactory ของคุณมีวิธี "สร้าง" จากนั้นใช้ลายเซ็นที่แตกต่าง "สร้าง (params)" และทำเสร็จแล้ว พารามิเตอร์ที่ไม่มีการขึ้นต่อกันมักจะได้รับการแก้ไขด้วยวิธีนี้ นอกจากนี้ยังลบหน้าที่ในการฉีดสิ่งต่าง ๆ เช่น "สาย" หรือ "จำนวนเต็ม" เพราะเพียงแค่เพิ่มจานหม้อไอน้ำพิเศษ
ใครสร้างใคร คอนเทนเนอร์ IoC สร้าง istances และโรงงานโรงงานสร้างส่วนที่เหลือ (โรงงานสามารถสร้างวัตถุต่าง ๆ ด้วยพารามิเตอร์ตามอำเภอใจดังนั้นคุณไม่จำเป็นต้องมีสถานะสำหรับโรงงาน) คุณยังสามารถใช้โรงงานเป็นเครื่องห่อหุ้มสำหรับคอนเทนเนอร์ IoC: โดยทั่วไปแล้วการพูด Injectin คอนเทนเนอร์ IoC นั้นแย่มากและเหมือนกับการใช้ตัวระบุบริการ บางคนแก้ไขปัญหาด้วยการห่อ IoC Container กับโรงงาน (ไม่จำเป็นอย่างเคร่งครัด แต่มีข้อได้เปรียบที่ลำดับชั้นได้รับการแก้ไขโดย Container และโรงงานทั้งหมดของคุณจะง่ายต่อการบำรุงรักษา)
//factory method
std::unique_ptr<myType> create(params){
auto istance = ioc->build<myType>(); //this code's agnostic to "myType" hierarchy
istance->setParams(params); //the customization you needed
return std::move(istance);
}
ยังไม่ละเมิดการฉีดพึ่งพาประเภทง่าย ๆ สามารถเป็นสมาชิกของชั้นเรียนหรือตัวแปรที่กำหนดขอบเขตท้องถิ่น นี่ดูเหมือนชัดเจน แต่ฉันเห็นคนฉีด "std :: vector" เพียงเพราะมีกรอบ DI ที่อนุญาต โปรดจำไว้เสมอกฎของ Demeter: "ฉีดเฉพาะสิ่งที่คุณต้องการฉีดเท่านั้น"