Bu, Doc Brown'a tamamlayıcı bir cevap olmayı ve Dinaiz'in hala Soru ile ilgili cevapsız yorumlarına cevap vermeyi amaçlar.
Muhtemelen ihtiyacınız olan şey DI yapmak için bir çerçevedir. Karmaşık hiyerarşilere sahip olmak, mutlaka kötü tasarım anlamına gelmez, ancak doğrudan D'ye enjekte etmek yerine TimeFactory aşağıdan yukarıya (A'dan D'ye) enjekte etmek zorunda kalırsanız, muhtemelen Bağımlılık Enjeksiyonu yapma biçiminizde yanlış bir şey vardır.
Bir singleton? Hayır teşekkürler. Yalnızca bir istance'a ihtiyacınız varsa bunu uygulama bağlamınızda paylaşmasını sağlayın (Infector ++ gibi bir DIC için IoC kabı kullanmak, sadece TimeFactory'yi tek istance olarak bağlamak için gereklidir), işte örnek (bu arada C ++ 11, fakat C ++. Zaten C ++ 11 için mi? Ücretsiz Sızdırmaz uygulama olsun):
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>();
Şimdi bir IoC kabının en iyi noktası, "D" sınıfı zaman fabrikasına ihtiyaç duyuyorsa, zaman fabrikasını D sınıfı için kurucu parametre olarak koymanız durumunda, zaman fabrikasını D'ye kadar geçirmenize gerek kalmamasıdır.
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
Gördüğünüz gibi TimeFactory'yi sadece bir kez enjekte ediyorsunuz. "A" nasıl kullanılır? Çok basit, her sınıfa enjekte edilir, ana yapıya yerleştirilir veya bir fabrika ile onaylanır.
auto myA1 = ioc.build<A>(); //A is not "single" so many different istances
auto myA2 = ioc.build<A>(); //can live at same time
A sınıfı her yaratışınızda, D ve D'ye kadar olan tüm bağımlılıklara otomatik olarak (tembel tanımlama) enjekte edilir, TimeFactory ile enjekte edilir, böylece sadece 1 yöntemi çağırdığınızda tam hiyerarşinize hazır olursunuz (ve hatta karmaşık hiyerarşiler bu şekilde çözülür) Çok sayıda kazan plakası kodunun çıkarılması): "new / delete" komutunu çağırmanız gerekmez ve bu çok önemlidir çünkü uygulama mantığını yapıştırıcı kodundan ayırabilirsiniz.
D, yalnızca D’nin sahip olabileceği bilgileri içeren Time nesneleri yaratabilir
Bu çok kolay, TimeFactory'nizde "create" yönteminiz var, sonra sadece farklı bir "create (params)" imzası kullanın ve bitirdiniz. Bağımlılık olmayan parametreler genellikle bu şekilde çözülür. Bu aynı zamanda, sadece fazladan kazan plakası eklediğinden, "dizeler" veya "tam sayılar" gibi şeyleri enjekte etme görevini de ortadan kaldırır.
Kim kimi yaratır? IoC konteyneri, durumlar ve fabrikalar yaratır, fabrikalar geri kalanı yaratır (fabrikalar isteğe bağlı parametrelerle farklı nesneler oluşturabilir, bu nedenle fabrikalar için bir duruma ihtiyacınız yoktur). Fabrikaları hala IoC Konteyner için sarmalayıcı olarak kullanabilirsiniz: genel olarak konuşursak, IoC Konteynerinin enjekte edilmesi çok kötüdür ve bir servis bulucu kullanmakla aynıdır. Bazı insanlar IoC Konteynerini bir fabrikaya sararak sorunu çözdü (bu kesinlikle gerekli değildir, ancak hiyerarşinin Konteyner tarafından çözülmesi ve tüm fabrikalarınızın bakımı daha kolay hale gelme avantajına sahiptir).
//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);
}
Ayrıca bağımlılık enjeksiyonunu kötüye kullanmayınız, basit tipler sadece sınıf üyeleri veya yerel kapsamlı değişkenler olabilir. Bu çok açık gözüküyor ancak insanların izin verdikleri bir DI çerçevesi olduğu için "std :: vector" enjekte ettiklerini gördüm. Demeter'in yasasını her zaman hatırlayın: "Yalnızca gerçekten enjekte etmeniz gerekenleri enjekte edin"