Bağımlılık Enjeksiyonu vs Fabrika Deseni


498

Bağımlılık Enjeksiyonu kullanımı için alıntılanan örneklerin çoğunu, fabrika modelini kullanarak da çözebiliriz. Kullanım / tasarım söz konusu olduğunda bağımlılık enjeksiyonu ile fabrika arasındaki fark bulanık veya incedir.

Birisi bana bunu nasıl kullandığınızı söylediğinde fark yaratır!

Bir zamanlar bir sorunu çözmek için StructureMap bir DI konteyneri kullandım, daha sonra basit bir fabrikada çalışacak şekilde yeniden tasarladım ve StructureMap referanslarını kaldırdım.

Biri bana aralarındaki farkın ne olduğunu ve neyin nerede kullanılacağını söyleyebilir mi, buradaki en iyi uygulama nedir?


21
Bu iki yaklaşım birbirine iltifat edemez: fabrika sınıflarını enjekte etmek için Bağımlılık Enjeksiyonunu kullanma?
Richard Ev

20
Bu soru içinde bazı kod ile bir cevap olsaydı gerçekten güzel olurdu! Hala DI'nin bir fabrikayı yaratılış için nasıl faydalı / farklı olacağını görmüyorum? Hangi nesnenin / uygulamanın oluşturulduğunu değiştirmek için fabrika sınıfındaki yalnızca bir satırı değiştirmeniz gerekir?
gideon

2
@gideon, uygulamanızı veya en azından fabrika sınıfını içeren modülü derlemeye zorlamaz mı?
lizerjik asit

1
@liortal evet doğru. Bu yorumdan beri DI üzerinde uzun bir çalışma yaptım ve şimdi DI'nin fabrika yöntemini bir adım öteye götürdüğünü anlıyorum.
gideon

1
Bu harika cevaba göz atın: stackoverflow.com/questions/4985455/… - çok iyi konuşuyor ve kod örnekleri sağlıyor.
Luis Perez

Yanıtlar:


293

Bir fabrika kullanırken kodunuz nesnelerin yaratılmasından hala sorumludur. DI tarafından bu sorumluluğu, kodunuzdan ayrı olan başka bir sınıfa veya çerçeveye dış kaynak olarak sağlıyorsunuz.


172
DI modeli herhangi bir çerçeve gerektirmez. DI olan fabrikaları manuel olarak yazarak DI yapabilirsiniz. DI çerçeveleri sadece kolaylaştırır.
Esko Luontola

28
@Perpetualcoder - Teşekkürler @Esko - Dont gelişmiş bazı üçüncü parti kütüphane anlamına gelen kelime çerçevesi yakalanmayın.
willcodejavaforfood

4
+1 @willcode teşekkürler! Bu yüzden bunun yerine config / xml dosyalarını değiştirmeniz gerekir. Anlıyorum. Wiki linki en.wikipedia.org/wiki/… fabrika modelini şu şekilde tanımlar:Manually-Injected Dependency
gideon

5
1 satır XML değiştirme vs 1 satır kod değiştirme avantajı yok. Açıklayabilir misiniz?
Rafael Eyng

1
"DI" yerine "fabrika" yerine OP yanıtını tekrarlayın, yine de mantıklı.
Edson Medina

219

Kavramları sade ve basit tutmayı öneririm. Bağımlılık Enjeksiyonu, yazılım bileşenlerini gevşek bir şekilde bağlamak için mimari bir modeldir. Fabrika düzeni, diğer sınıfların nesnelerini yaratma sorumluluğunu başka bir varlığa ayırmanın sadece bir yoludur. Fabrika modeli DI'yi uygulamak için bir araç olarak adlandırılabilir. Bağımlılık enjeksiyonu, yapıcılar kullanılarak, eşleme xml dosyaları vb. Kullanılarak DI gibi birçok şekilde uygulanabilir.


4
Fabrika Paterninin Bağımlılık Enjeksiyonunu uygulamanın yollarından biri olduğu doğrudur. Fabrika Deseni karşısında Bağımlılık Enjeksiyonu kullanmanın bir başka yararı da DI Frameworks, soyutlamalarınızı somut tiplerinize nasıl kaydedeceğiniz konusunda esneklik vermesidir. Yapılandırma, XML veya Otomatik Yapılandırma gibi Kod gibi. Bu esneklik, nesnelerinizin ömrünü yönetmenizi veya arabirimlerinizi nasıl ve ne zaman kaydedeceğinize karar vermenizi sağlayacaktır.
Teoman shipahi

1
Fabrika düzeni DI'den daha yüksek seviyede soyutlama sunar. Bir fabrika, DI'nin yaptığı gibi yapılandırma seçenekleri sunabilir, ancak aynı zamanda tüm bu yapılandırma ayrıntılarını gizlemeyi de seçebilir, böylece fabrika, müşteri bilmeden tamamen farklı bir uygulamaya geçmeye karar verebilir. DI tek başına buna izin vermez. DI, müşterinin istediği değişiklikleri belirtmesini gerektirir.
nöron

1
Güzel cevap. Birçoğu şu soru ile karıştırıyor: "Hangi pattens'i seçmeliyim?" Aslında, tasarım kalıpları problemi uygun durumlarda çözmenin bir yoludur. Hangi tasarım desenini kullanmanız gerektiğini bilmiyorsanız veya "Deseni nereye uygulamalıyım?" o zaman buna ihtiyacınız yok.
Benyi

2
Fabrika Deseninin IoC'yi (DI değil) uygulamak için bir araç olduğunu söylemek daha doğru olur.
DI'nin

185

Bağımlılık Enjeksiyonu

Bir otomobil, parçaları kendisinin somutlaştırmak yerine, çalışması gereken parçaları ister .

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Fabrika

Tam bir nesne yapmak için parçaları bir araya getirir ve beton tipini arayandan gizler.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Sonuç

Gördüğünüz gibi, Fabrikalar ve DI birbirini tamamlıyor.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

Goldilocks ve üç ayı hatırlıyor musun? Bağımlılık enjeksiyonu böyle bir şey. İşte aynı şeyi yapmanın üç yolu.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Örnek 1 - Bu en kötüsü çünkü bağımlılığı tamamen gizliyor. Yönteme bir kara kutu olarak bakarsanız, bir arabaya ihtiyaç duyduğuna dair hiçbir fikriniz olmazdı.

Örnek 2 - Bu biraz daha iyi çünkü artık bir araba fabrikasından geçtiğimiz için bir arabaya ihtiyacımız olduğunu biliyoruz. Ama bu sefer çok fazla yoldan geçiyoruz çünkü aslında tüm yöntemin ihtiyacı olan bir araba. Araba, yöntemin dışında inşa edilebildiğinde ve geçtiğinde, sadece arabayı inşa etmek için bir fabrikadan geçiyoruz.

Örnek 3 - Bu idealdir çünkü yöntem tam olarak neye ihtiyaç duyduğunu sorar . Çok fazla veya çok az değil. Sadece MockCars oluşturmak için bir MockCarFactory yazmak zorunda değilim, sahte düz geçebilir. Doğrudan ve arayüz yalan söylemez.

Misko Hevery tarafından hazırlanan bu Google Tech Talk inanılmaz ve örneğimi türettiğim şeyin temelini oluşturuyor. http://www.youtube.com/watch?v=XcT4yYu_TTs


1
Fabrika Deseni DI olarak enjekte edilir.
Mangesh Pimpalkar

7
@PhilGoetz Açıkladığınız şey, daha çok Servis Bulucu düzeni gibi geliyor. Benzer hedefleri var, çünkü hizmetleri tüketicilerinden ayırmayı amaçlıyorlar. Bununla birlikte, Servis Bulucu deseninin birçok dezavantajı vardır. Temel olarak, bağımlılıkları gizlemek iyi bir şey değildir . Tüketicinin hala bağımlılıklarını alması gerekiyor, ancak açık bir arayüz tanımlamak yerine, 'gizlice' geçiyor ve küresel duruma güveniyorlar. Örnekte, tüketicinin fabrika hakkında hiçbir fikri yoktur, sadece neye ihtiyacı olduğunu sorar ve bu ihtiyacın nasıl inşa edildiği ile ilgilenmek zorunda değildir.
Despertar

1
@MatthewWhited Çoğu tasarım kararının bir ödülü var. DI ile esneklik, şeffaflık ve daha test edilebilir bir sistem elde edersiniz, ancak bağırsaklarınızı ortaya çıkarmanız pahasına. Birçok insan bunu kabul edilebilir bir takas olarak görür. Bu, DI'nin her zaman en iyi çözüm olduğu anlamına gelmez ve bu soru bununla ilgili değildir. Örnek, her birinin iyi ve kötü kullanımlarını göstererek DI ve fabrika deseni arasındaki farkı göstermek içindir.
Despertar

3
Bu bir DI modeli değil, bu sadece IoC'nin bir uygulaması. DI, doğru bağımlılığı belirlemek ve nesne oluşturma sırasında yapıcıya enjekte etmek için bir ServiceLocator kullanır, kodunuz yalnızca sınıf oluşturma nesnelerin oluşturulmasını ayırır.
Diego Mendes

3
@DiegoMendes Açıkladığınız şey DI'yi otomatik hale getiren bir çerçevedir. ServiceLocator dediğiniz gibi DI sizin için yapar. Gösterdiğim şey, herhangi bir süslü çerçeve gerektirmeyen desenin kendisidir. Bkz. Stackoverflow.com/a/140655/1160036 veya en.wikipedia.org/wiki/… : "[çerçeve listesi] bağımlılık enjeksiyonunu destekler, ancak bağımlılık enjeksiyonu yapması gerekmez". Ayrıca, "Enjeksiyon bağımlılığın bağımlı bir nesneye geçmesidir". Çok basit bir konsepti karmaşıklaştırıyorsunuz.
Despertar

50

Bağımlılık Enjeksiyonu (DI) ve Fabrika Kalıplarının benzer olmasının nedeni, bir yazılım mimarisi olan İnversiyon Kontrolün (IoC) iki uygulaması olmasıdır. Basitçe söylemek gerekirse, onlar aynı soruna iki çözümdür.

Yani soruyu cevaplamak için Fabrika kalıbı ve DI arasındaki temel fark nesne referansının nasıl elde edildiği. Bağımlılık enjeksiyonu ile adından da anlaşılacağı gibi referans enjekte edilir veya kodunuza verilir. Fabrika kalıbı ile, kodunuzun nesneyi alması için kodunuz referans istemelidir. Her iki uygulama, kod ile kod tarafından kullanılan nesne başvurusunun temel sınıfı veya türü arasındaki bağlantıyı kaldırır veya ayırır.

Fabrika modellerinin (veya nesne referanslarını döndüren yeni fabrikaları döndüren fabrikalar olan Soyut Fabrika modellerinin), çalışma zamanında istenen nesne türünü veya sınıfını dinamik olarak seçmek veya bunlara bağlantı vermek için yazılabileceğini belirtmek gerekir. Bu, onları IoC'nin başka bir uygulaması olan Servis Bulucu modeline (DI'den çok daha fazla) benzer hale getirir.

Fabrika tasarım deseni oldukça eski (Yazılım açısından) ve bir süredir var. Mimari model IoC'nin son popülerliğinden bu yana yeniden canlanıyor.

Sanırım IoC tasarım kalıpları söz konusu olduğunda: enjektörler enjekte ediyor, konumlandırıcılar konumlanıyor ve fabrikalar yeniden düzenleniyor.


3
Bu en iyi cevaptır ... diğer cevaplar ya IoC'den bahsetmez ya da DI'nin bir çeşit IoC olduğunu kabul etmez.
Hooman Bahreini

Teşekkürler, IOC'yi ilk incelediğimde, bunun fabrika modelinin sadece bir başka formu olduğunu neredeyse çığlık attılar, birbirlerine gerçekten benzedikleri ortaya çıktı
Harvey Lin

40

Bağımlılık enjeksiyonu ile çözülmesi kolay, bir takım fabrikalarla bu kadar kolay çözülemeyen sorunlar var.

Bir yandan, kontrol ve bağımlılık enjeksiyonu (IOC / DI) inversiyonu ile diğer yandan bir servis bulucu veya bir fabrika paketi (fabrika) arasındaki farklardan bazıları:

IOC / DI, kendi başına etki alanı nesneleri ve hizmetlerinin eksiksiz bir ekosistemidir. Sizin için her şeyi sizin belirlediğiniz şekilde ayarlar. Alan adı nesneleri ve hizmetler konteyner tarafından inşa edilir ve kendilerini inşa yoktur: Onlar bu nedenle yok herhangi kap veya herhangi bir fabrikaların üzerinde bağımlılıkları. IOC / DI, tüm konfigürasyonları uygulamanızın en üst katmanında (GUI, Web ön ucu) tek bir yerde (konteynerin yapısı) son derece yüksek bir konfigürasyona izin verir.

Fabrika, alan adı nesnelerinizin ve hizmetlerinizin bazılarını soyutlar. Ancak etki alanı nesneleri ve hizmetleri, kendilerini nasıl oluşturacaklarını ve bağımlı oldukları her şeyi nasıl elde edeceklerini bulmaktan hala sorumludur. Tüm bu "aktif" bağımlılıklar uygulamanızdaki tüm katmanlara kadar filtreler. Her şeyi yapılandırmak için gidilecek tek bir yer yok.


26

DI'nin bir dezavantajı, nesneleri mantıkla başlatamamasıdır. Örneğin, rastgele bir adı ve yaşı olan bir karakter oluşturmam gerektiğinde, DI fabrika modeline göre seçim değildir. Fabrikalarla, rastgele algoritmayı "Değişenleri kapsüle et" adlı tasarım modellerinden birini destekleyen nesne oluşturma işleminden kolayca kapsülleyebiliriz.


22

Yaşam döngüsü yönetimi, kapsayıcıların örnekleme ve enjeksiyona ek olarak üstlendiği sorumluluklardan biridir. Konteynerin, örneklemeden sonra bazen bileşenlere bir referans tutması, bir fabrika değil, bir "konteyner" olarak adlandırılmasının nedenidir. Bağımlılık enjeksiyon kapları genellikle sadece yaşam döngülerini yönetmek için ihtiyaç duyduğu veya tekil veya sinek ağırlıkları gibi gelecekteki enjeksiyonlar için yeniden kullanılan nesnelere referans verir. Kapsayıcıya yapılan her çağrı için bazı bileşenlerin yeni örneklerini oluşturmak üzere yapılandırıldığında, kap genellikle oluşturulan nesneyi unutur.

Gönderen: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

DI'nin fabrikalarda bir tür soyutlama katmanı olduğuna inanıyorum, ancak aynı zamanda soyutlamanın ötesinde faydalar da sağlıyorlar. Gerçek bir fabrika, tek bir türün nasıl başlatılacağını ve yapılandırılacağını bilir. İyi bir DI katmanı, konfigürasyon yoluyla birçok türü somutlaştırma ve yapılandırma yeteneği sağlar.

Açıkçası, inşaatlarında nispeten istikrarlı bir iş mantığı gerektiren birkaç basit tipte bir proje için, fabrika modelinin anlaşılması, uygulanması ve iyi çalıştığı basittir.

OTOH, uygulamalarını sık sık değiştirmeyi düşündüğünüz çok sayıda türü içeren bir projeniz varsa DI, fabrikalarınızı yeniden derlemek zorunda kalmadan çalışma zamanında bunu yapma esnekliği sağlar.


14

teori

Dikkate alınması gereken iki önemli nokta vardır:

  1. Nesneleri kim oluşturur?

    • [Fabrika]: Yazmanız gereken HOW nesnesi oluşturulmalıdır. Oluşturma mantığını içeren ayrı bir Factory sınıfınız var.
    • [Bağımlılık Enjeksiyonu]: Pratik durumlarda harici çerçeveler tarafından yapılır (örneğin Java'da bahar / ejb / guice olur). Enjeksiyon, yeni nesnelerin açık bir şekilde oluşturulması olmadan "sihirli bir şekilde" gerçekleşir
  2. Ne tür nesneleri yönetiyor:

    • [Fabrika]: genellikle durum bilgisi olan nesnelerin oluşturulması için sorumlu
    • [Bağımlılık Enjeksiyonları] Vatansız nesneler oluşturma olasılığı daha yüksektir

Tek bir projede hem fabrika hem de bağımlılık enjeksiyonunun nasıl kullanılacağına dair pratik örnek

  1. Ne inşa etmek istiyoruz

Orderline adı verilen birden fazla giriş içeren sipariş oluşturmak için uygulama modülü.

  1. Mimari

Aşağıdaki katman mimarisini oluşturmak istediğimizi varsayalım:

resim açıklamasını buraya girin

Etki alanı nesneleri, veritabanında depolanan nesneler olabilir. Havuz (DAO), nesnelerin veritabanından alınmasına yardımcı olur. Hizmet, diğer modüllere API sağlar. Üzerinde operasyonlar için alows ordermodülü

  1. Domain Katmanı ve fabrika kullanımı

Veritabanında yer alacak varlıklar Order ve OrderLine'dır. Siparişte birden fazla OrderLines olabilir. Order ve OrderLine arasındaki ilişki

Şimdi önemli bir tasarım parçası geliyor. Bunun dışındaki modüller OrderLines'ı kendi başlarına oluşturmalı ve yönetmeli mi? Hayır. Sipariş Satırı yalnızca Siparişle ilişkilendirilmişken mevcut olmalıdır. İç uygulamayı dış sınıflara gizleyebilmeniz daha iyi olur.

Peki OrderLines hakkında bilgi sahibi olmadan Order nasıl oluşturulur?

Fabrika

Yeni sipariş oluşturmak isteyen biri OrderFactory'yi kullandı (bu Sipariş'i nasıl yarattığımızla ilgili ayrıntıları gizleyecekti).

resim açıklamasını buraya girin

Bu IDE içine nasıl görüneceğini. İçerideki kurucu yerine domainpaket dışındaki sınıflar kullanılırOrderFactoryOrder

  1. Bağımlılık Enjeksiyonu Bağımlılık enjeksiyonu daha çok depo ve servis gibi durumsuz katmanlarda kullanılır.

OrderRepository ve OrderService bağımlılık enjeksiyon çerçevesi tarafından yönetilir. Havuz, veritabanındaki CRUD işlemlerini yönetmekten sorumludur. Hizmet Havuzu enjekte eder ve doğru etki alanı sınıflarını kaydetmek / bulmak için kullanır.

resim açıklamasını buraya girin


Lütfen bunu açıklığa kavuşturabilir misiniz? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsNedenini anlamıyorum
Maksim Dmitriev

2
Durum bilgisi olan nesnelerin, genellikle bağımlılık enjeksiyonunu kullanmadığınız verilerinizi veritabanına eşlediğiniz uygulama etki alanı katmanında olması muhtemeldir. Fabrika sık sık karmaşık nesnelerin ağacından AggregateRoot oluşturmak için kullanılır
Marcin Szymczak

12

Bu sorunun eski olduğunu biliyorum ama beş sentimi eklemek istiyorum,

Bağımlılık enjeksiyonunun (DI) yapılandırılabilir bir Fabrika Deseni (FP) gibi birçok açıdan olduğunu düşünüyorum ve bu anlamda DI ile yapabileceğiniz her şeyi böyle bir fabrika ile yapabileceksiniz.

Aslında, örneğin yay kullanıyorsanız, otomatik kablolama kaynakları (DI) veya bunun gibi bir şey yapma seçeneğiniz vardır:

MyBean mb = ctx.getBean("myBean");

Ve sonra bir şey yapmak için o 'mb' örneğini kullanın. Bu size bir örnek verecek bir fabrikaya çağrı değil mi ??

FP örneklerinin çoğu arasında fark ettiğim tek gerçek fark, "myBean" ın bir xml'de veya başka bir sınıfta ne olduğunu yapılandırabilmenizdir ve bir çerçeve fabrika olarak çalışır, ancak bunun dışında aynı şeydir ve kesinlikle bir config dosyasını okuyan veya gerektiğinde uygulamayı alan bir Fabrikaya sahip olabilir.

Ve bana fikrimi sorarsan (Ve bilmediğini biliyorum), DI'nin aynı şeyi yaptığını ama sadece gelişime daha fazla karmaşıklık kattığına inanıyorum, neden?

iyi, bir şey için, DI ile otomatik olarak bağladığınız herhangi bir fasulye için uygulamanın ne olduğunu bilmeniz için, yapılandırmanın kendisine gitmelisiniz.

ama ... ya kullandığınız nesnenin uygulanmasını bilmek zorunda kalmayacağınız vaadine ne dersiniz? pfft! ciddi anlamda? böyle bir yaklaşım kullandığınızda ... uygulamayı yazan ile aynı değil misiniz ?? ve yapmasanız bile, neredeyse her zaman uygulamanın nasıl yapması gerektiğini nasıl yaptığına bakarak öyle değil mi ??

ve son bir kere, bir DI çerçeve vaat ne kadar önemli değil sen şeyler inşa edeceğini size ayrılmış size her şeyi inşa bir çerçeve kullanıyorsanız, kendi sınıfları için hiçbir bağımlılıkları ile, ondan, onu aroud size varsa yaklaşımı veya çerçeveyi değiştirmek kolay bir iş olmayacak ... HİÇ! ... ancak, işiniz için en iyi çözümden endişe etmek yerine, her şeyi belirli bir çerçevede oluşturduğunuzdan, bunu yaparken bir biiig proben ile karşılaşacaksınız.

Aslında, görebildiğim bir FP veya DI yaklaşımı için tek gerçek iş uygulaması, çalışma zamanında kullanılan uygulamaları değiştirmeniz gerekiyorsa , ancak en azından bildiğim çerçeveler bunu yapmanıza izin vermiyorsa, ayrılmanız gerekiyor geliştirme zamanında yapılandırma her şey mükemmel bir başka bir yaklaşım kullanmak gerekiyorsa.

Yani, aynı uygulamada iki kapsamda farklı performans gösteren bir sınıfım varsa (diyelim ki, bir holdingin iki şirketi), iki farklı fasulye oluşturmak için çerçeveyi yapılandırmam ve her birini kullanmak için kodumu uyarlamam gerekiyor. Ben sadece böyle bir şey yazar gibi değil mi:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

bununla aynı:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

Ve bu:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

Her durumda, ister sınıf ister yapılandırma dosyaları olsun, uygulamanızdaki bir şeyi değiştirmeniz gerekecektir, ancak bunu yeniden konuşlandırmanız gerekecektir.

Böyle bir şey yapmak hoş olmaz mıydı:

MyBean mb = (MyBean)MyFactory.get("mb"); 

Ve bu şekilde, fabrika kodunu kayıtlı kullanıcı kuruluşuna bağlı olarak çalışma zamanında doğru uygulamayı almak için ayarladınız ?? Şimdi bu yardımcı olur. Yeni sınıflarla yeni bir kavanoz ekleyebilir ve kuralları çalışma zamanında bile ayarlayabilir (veya bu seçeneği açık bırakırsanız yeni bir yapılandırma dosyası ekleyebilirsiniz), mevcut sınıflarda değişiklik olmaz. Bu Dinamik bir fabrika olurdu!

her işletme için iki konfigürasyon yazmak zorunda olmaktan ve hatta her biri için iki farklı uygulamaya sahip olmaktan daha yararlı olmaz mı?

Bana söyleyebilirsin, anahtarı çalışma zamanında hiç yapmam gerekmiyor, bu yüzden uygulamayı yapılandırıyorum ve sınıfı devralırsam veya başka bir uygulama kullanırsam, sadece yapılandırmayı değiştirir ve yeniden konuşlandırırım. Tamam, bu bir fabrika ile de yapılabilir. Ve dürüst ol, bunu kaç kez yapıyorsun? belki sadece şirketinizde başka bir yerde kullanılacak bir uygulamanız olduğunda ve kodu başka bir ekibe geçirdiğinizde ve bunun gibi şeyler yaparlar. Ama hey, bu fabrika ile de yapılabilir ve dinamik bir fabrika ile daha da iyi olurdu!

Her neyse, yorum bölümü beni öldürmen için açıksa.


3
Çok fazla geliştirici, Bağımlılık Enjeksiyonu çerçevelerinin yeni bir şey getirmek için oluşturulduğunu düşünüyor. İyi açıkladığınız gibi, geleneksel fabrikalar (çoğu zaman soyut fabrika) bağımlılık tersinin aynı rolünü oynayabilir. İnversiyon mu Enjeksiyon mu? Benim için, Bağımlılık Enjeksiyonu çerçevesinin tek "yararı", bir bağımlılık eklendiğinde / değiştirildiğinde kodu değiştirmemiz / yeniden derlemememizdir (çoğunlukla Spring gibi XML ile yapılandırılabilir). Neden yeniden derlemekten kaçının? Bağımlılığı / fabrikayı değiştirirken potansiyel insan hatalarından kaçınmak için. Ama büyük
IDE'lerimizle

6

IOC, iki yolla uygulanan bir kavramdır. Bağımlılık yaratma ve bağımlılık enjeksiyonu, Fabrika / Soyut fabrika bağımlılık yaratma örneğidir. Bağımlılık enjeksiyonu yapıcı, ayarlayıcı ve arayüzdür. IOC'nin özü, somut sınıflara bağlı olmamak, ancak yöntemlerin özetini (bir Arayüz / soyut sınıf diyelim) tanımlamak ve bu özeti somut sınıf yöntemini çağırmak için kullanmaktır. Fabrika deseni gibi temel sınıfı veya arayüzü döndürün. Benzer bağımlılık enjeksiyonu, nesneler için değeri ayarlamak için temel sınıf / arayüz kullanır.


4

Bağımlılık enjeksiyonu ile müşterinin bağımlılıklarını kendi başına alması gerekmez, hepsi önceden hazırlanır.

Fabrikalarda, birisi üretilen nesneleri ihtiyaç duydukları yere götürmek için bunları çağırmalıdır.

Aradaki fark çoğunlukla fabrikanın çağrılması ve inşa edilen nesnenin getirilmesinin yapıldığı tek satırda yatmaktadır.

Ancak fabrikalarda bu 1 satırı her yere yazmanız gerekiyor, böyle bir nesneye ihtiyacınız var. DI ile kablolamayı (kullanım ve oluşturulan nesne arasındaki ilişki) bir kez oluşturmanız ve daha sonra her yerde nesnenin varlığına güvenmeniz gerekir. Öte yandan, DI genellikle hazırlık tarafında biraz daha fazla (çerçeveye bağlı olarak) çalışmayı gerektirir.


3

En kısa sürede DI hakkında okudum ve bu yazı sona erdi aynı soru vardı. Sonunda bunu anladım ama yanılıyorsam lütfen düzeltin.

"Uzun zaman önce kendi yönetim organları kendi yazılı kurallarına göre kontrol ve kararlar alan küçük krallıklar vardı. Daha sonra bir dizi kurala (anayasa) sahip olan ve mahkemeler aracılığıyla uygulanan tüm bu küçük yönetim organlarını ortadan kaldıran büyük bir hükümet kuruldu"

Küçük krallıkların yönetim organları "Fabrikalar" dır.

Büyük hükümet "Bağımlılık Enjektörü" dür.


1
Öyleyse, önceki büyük bir hükümeti şimdi ne zaman büyük olacak? Hangi önlemle?
Mahkum ZERO

3

Gerçek bir örnekte iki (ve diğerleri) yaklaşımın karşılaştırılması için bu bağlantıya bakabilirsiniz .

Temel olarak, gereksinimler değiştiğinde, DI yerine fabrikalar kullanırsanız daha fazla kod değiştirirsiniz.

Bu, manuel DI için de geçerlidir (yani, nesnelerinize bağımlılık sağlayan harici bir çerçeve olmadığında, ancak bunları her yapıcıya ilettiğinizde).


3

Buradaki cevapların çoğu, her ikisinin kavramsal farkını ve uygulama ayrıntılarını açıklar. Ancak IMO'nun en önemli olduğu ve OP'nin sorduğu uygulamadaki fark hakkında açıklama bulamadım. Bu konuyu tekrar açayım ...

Birisi bana bunu nasıl kullandığınızı söylediğinde fark yaratır!

Kesinlikle. % 90'da Fabrika veya DI'yi kullanarak nesne referansı alabilirsiniz ve genellikle ikincisiyle sonuçlanırsınız. Diğer% 10'luk durumlarda ise Fabrika kullanımı sadece doğru yoldur . Bu durumlar çalışma zamanı parametrelerinde değişkene göre nesne edinmeyi içerir. Bunun gibi:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

Bu durumda DI'den almak clientmümkün değildir (veya en azından çirkin bir geçici çözüm gerektirir). Karar vermek için genel bir kural olarak: herhangi bir çalışma zamanı hesaplanmış parametre olmadan bir bağımlılık elde edilebilirse, DI tercih edilir, aksi takdirde Fabrika kullanın.


2

Ben DI bir fasulye yapılandırma veya örnekleme yolu olduğuna inanıyorum. DI, yapıcı, setter-getter vb.Gibi birçok şekilde yapılabilir.

Fabrika modeli, fasulyeleri örneklemenin başka bir yoludur. bu desen esas olarak fabrika tasarım desenini kullanarak nesneler oluşturmanız gerektiğinde kullanılacaktır, çünkü bu deseni kullanırken bir çekirdeğin özelliklerini yapılandırmazsınız, yalnızca nesneyi başlatırsınız.

Bu bağlantıyı kontrol edin: Bağımlılık Enjeksiyonu


2

Binoj,

Birini diğerinden seçmek zorunda olduğunu sanmıyorum.

Bağımlı bir sınıfı veya arabirimi bir sınıf yapıcısına veya ayarlayıcısına taşıma eylemi DI modelini izler. Yapıcıya veya kümeye ilettiğiniz nesne Factory ile uygulanabilir.

Ne zaman kullanılır? Geliştirici tekerlekli evinizde bulunan deseni veya desenleri kullanın. En rahat hissettikleri ve anlaşılması en kolay buldukları şey.


2

3 önemli cismin nesneleri ve bunların kullanımını yönettiğine inanıyorum:
1. Örnekleme (varsa sınıfın başlatılması ile birlikte).
2. Gerekli olan yere enjeksiyon (bu şekilde oluşturulan örneğin).
3. Yaşam döngüsü yönetimi (bu şekilde oluşturulan örneğin).

Fabrika düzeni kullanılarak ilk yön (örnekleme) elde edilir, ancak geri kalan ikisi sorgulanabilir. Diğer örnekleri kullanan sınıf, gevşek bağlantı yeteneklerini engelleyen fabrikaları (oluşturulmakta olan örnekler yerine) kodlamalıdır. Ayrıca, yaşam döngüsü yönetimiÖrneğin, bir fabrikanın birden fazla yerde kullanıldığı büyük bir uygulamada bir meydan okuma haline gelir (özellikle fabrika, iade ettiği örneğin yaşam döngüsünü yönetmezse, çirkinleşir).

Öte yandan bir DI (IoC paterni) kullanarak, 3'ün tamamı kodun (DI kabına) dışında soyutlanır ve yönetilen çekirdeğin bu karmaşıklık hakkında hiçbir şeye ihtiyacı yoktur. Gevşek Kavrama , çok önemli bir mimari hedefe rahatça sessizce ulaşılabilir. Bir diğer önemli mimari amaç, endişelerin ayrılması fabrikalardan çok daha iyi elde edilebilir.

Fabrikalar küçük uygulamalar için uygun olabilirken, büyük fabrikalar DI'yi fabrikalara göre seçmek daha iyi olacaktır.


1

Düşüncelerim:

Dependecy Injection: ortak çalışanları yapıcılara parametre olarak iletir. Bağımlılık Enjeksiyon Çerçevesi: Oluşturuculara parametre olarak iletilecek nesneleri oluşturmak için genel ve yapılandırılabilir bir fabrika.


1
Evet kesinlikle. Bu soru-cevaptaki Bağımlılık Enjeksiyonu'ndan (DI) bahsedilenlerin neredeyse tamamı, bu tanımın aksine terimi yanlış kullanır. Bağımlılık Enjeksiyon Kabı (DIC), nesne oluşturmak için genel ve yapılandırılabilir bir fabrika görevi gören en yaygın çerçevedir.
CXJ

1

Enjeksiyon Çerçevesi, Fabrika Modelinin bir uygulamasıdır.

Her şey gereksinimlerinize bağlıdır. Fabrika şablonunu bir uygulamada uygulamanız gerekiyorsa, gereksinimlerinizin sayısız enjeksiyon çerçevesi uygulamasından biri tarafından karşılanması büyük olasılıktır.

Kendi çözümünüzü ancak gereksinimleriniz 3. taraf çerçevelerinden herhangi biri tarafından karşılanamıyorsa sunmalısınız. Ne kadar çok kod yazarsanız, o kadar çok kod yazmanız gerekir. Kod bir varlık değil bir yükümlülüktür.

Hangi uygulamayı kullanmanız gerektiği konusundaki tartışmalar, uygulamanızın mimari ihtiyaçlarını anlamak kadar önemli değildir.


1

Fabrika Tasarım Desen

Fabrika tasarım deseni ile karakterize edilir

  • Bir Arayüz
  • Uygulama sınıfları
  • Bir fabrika

Kendinizi aşağıdaki gibi sorguladığınızda birkaç şeyi gözlemleyebilirsiniz

  • Fabrika, uygulama sınıfları için ne zaman nesne oluşturacak - çalışma zamanı veya derleme zamanı?
  • Uygulamayı çalışma zamanında değiştirmek isterseniz ne olur? - Mümkün değil

Bunlar Bağımlılık enjeksiyonu ile ele alınmaktadır.

Bağımlılık enjeksiyonu

Bağımlılığı enjekte etmenin farklı yolları olabilir. Basitlik için Arayüz Enjeksiyonu ile gidelim

DI'de, konteyner gerekli örnekleri oluşturur ve bunları nesneye "enjekte eder".

Böylece statik örneklemeyi ortadan kaldırır.

Misal:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

Bir yüz değerinden aynı görünüyorlar

Çok basit bir ifadeyle, bir Üretim Deseni olan Fabrika Deseni, bize bir nesne yaratmamıza yardımcı olur - "Nesne oluşturmak için bir arayüz tanımla". Nesne havuzunun anahtar değerine sahip bir türümüz varsa (örn. Sözlük), anahtarı Fabrika'ya geçirerek (Basit Fabrika Kalıbı'na atıfta bulunuyorum) Türü çözebilirsiniz. İş bitmiş! Öte yandan Bağımlılık Enjeksiyon Çerçevesi (Yapı Haritası, Ninject, Birlik ... vb.) Aynı şeyi yapıyor gibi görünüyor.

Ama ... "Tekerleği yeniden icat etme"

Mimari açıdan bakıldığında, bağlayıcı bir katman ve "Tekerleği yeniden icat etme".

Kurumsal düzeyde bir uygulama için, DI kavramı daha çok bağımlılıkları tanımlayan mimari bir katmandır. Bunu daha da basitleştirmek için, bunu bağımlılık çözümlemesi yapan ayrı bir sınıf kütüphanesi projesi olarak düşünebilirsiniz. Ana uygulama, Bağımlılık çözümleyicinin diğer somut uygulamalara ve bağımlılık çözümlemesine atıfta bulunduğu bu projeye dayanmaktadır.

Bir Fabrikadan "GetType / Create" e ek olarak, çoğu zaman daha fazla özelliğe ihtiyacımız yoktur (bağımlılıkları tanımlamak için XML kullanma yeteneği, alay ve birim testi vb.). Yapı Haritası'na başvurduğunuzdan , Yapı Haritası özellik listesine bakın . Açıkça basit nesne Eşleme çözmekten daha fazlasıdır. Tekerleği yeniden icat etme!

Eğer sahip olduğunuz tek şey bir çekiçse, her şey çivi gibi görünür

Gereksinimlerinize ve ne tür bir uygulama oluşturduğunuza bağlı olarak bir seçim yapmanız gerekir. Yalnızca birkaç projesi varsa (bir veya iki olabilir ..) ve birkaç bağımlılık içeriyorsa, daha basit bir yaklaşım seçebilirsiniz. Basit bir 1 veya 2 veritabanı çağrısı için Entity Framework kullanımı üzerinden ADO .Net veri erişimini kullanmak gibi, burada EF tanıtımı bu senaryoda aşırıya kaçıyor.

Ancak daha büyük bir proje için veya projeniz daha büyük olursa, bir çerçeveye sahip bir DI katmanına sahip olmanızı ve kullandığınız DI çerçevesini değiştirmek için yer açmanızı şiddetle tavsiye ederim (Ana Uygulamada bir Cephe Kullan (Web Uygulaması, Web Api, Masaüstü) ..vb.).


1

Bir fabrika ile ilgili arayüzleri gruplayabilirsiniz, yani Geçilen parametreler bir fabrikada gruplanabilirse constructor overinjection, bu koda bakmak için iyi bir çözümdür *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Yapıcıya bakın, sadece IAddressModelFactoryoradan geçmeniz gerekir , bu yüzden daha az parametre *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Sen görmek CustomerController, Evet bu kadar görebilirsiniz geçirilen bir çok parametre bir constructor overinjectionama DI nasıl çalıştığını budur. Ve hiçbir şey yanlış değil CustomerController.

*) Kod nopCommerce adresinden alınmıştır.


1

Basit bir ifadeyle, Bağımlılık Enjeksiyonu vs Fabrika yöntemi sırasıyla itme-çekme mekanizmasını ifade eder.

Çekme mekanizması : sınıf dolaylı olarak beton sınıflarına bağımlı olan Fabrika Metoduna bağımlıdır.

İtme mekanizması : Kök bileşen, tüm bağımlı bileşenlerle tek bir yerde yapılandırılabilir ve böylece yüksek bakım ve gevşek bağlantıyı teşvik eder.

Fabrika yöntemi ile sorumluluk, bağımlılık enjeksiyonunda olduğu gibi, sorumluluğun dışarıdan tedarik edildiği (yine de soyutlama sızıntısı pahasına) yeni bir nesne yaratmak için (dolaylı olarak da olsa) sorumlulukla ilgilidir.


0

Bence bunlar dik ve birlikte kullanılabilir. Size yakın zamanda işyerinde karşılaştığım bir örneği göstereyim:

DI için Java'da Spring çerçevesini kullanıyorduk. Bir singleton sınıfı ( Parent), başka bir sınıfın ( Child) yeni nesnelerini başlatmak zorundaydı ve bunların karmaşık ortak çalışanları vardı:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

Bu örnekte, yalnızca kurucuya iletmek için örnekler Parentalmak DepXzorundadır Child. Bununla ilgili sorunlar:

  1. Parentolması Childgerekenden daha fazla bilgiye sahip
  2. Parent olması gerekenden daha fazla ortak çalışanı var
  3. İçin bağımlılıkları ekleme ChilddeğiştirmeyiParent

İşte Factorytam olarak burada mükemmel bir uyum olacağını fark ettim :

  1. Görüldüğü Childgibi , sınıfın gerçek parametreleri hariç hepsini gizlerParent
  2. ChildDI konfigürasyonunda merkezileştirilebilen a oluşturma bilgisini içerir .

Bu basitleştirilmiş Parentsınıf ve ChildFactorysınıftır:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

Bu zamanda ne tür nesnelere ihtiyacınız olduğunu tam olarak bildiğinizde bağımlılık enjeksiyonu kullanırsınız. Fabrika düzeni söz konusu olduğunda, tam olarak ne tür bir nesneye ihtiyacınız olduğundan emin olmadığınız için, fabrika oluşturma işlemini fabrikaya devredersiniz.


-1

Her ikisini de , benden sonra sürdürmesi gereken geliştiriciler için daha fazla okunabilirliğe sahip bir Kontrol Ters Çevirme stratejisi oluşturmak için kullanıyorum .

Farklı Katman nesnelerimi (İşletme, Veri Erişimi) oluşturmak için bir Fabrika kullanıyorum.

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Başka bir geliştirici bunu görecek ve bir Business Layer nesnesi oluştururken BusinessFactory'de görünüyor ve Intellisense geliştiriciye oluşturmak için mümkün olan tüm Business Layers'ı sunuyor. Oyunu oynamak zorunda değilim, oluşturmak istediğim arayüzü buluyorum.

Bu yapı zaten Kontrolün Tersine Çevirilmesi. Artık belirli bir nesneyi oluşturmaktan sorumlu değilim. Ancak, işleri kolayca değiştirebilmek için Bağımlılık Enjeksiyonunu sağlamanız gerekir. Kendi özel Bağımlılık Enjeksiyonunuzu oluşturmak çok saçma, bu yüzden Unity kullanıyorum. CreateCarBusiness () içinde Unity'den hangi sınıfın buna ait olduğunu ve ömrünü çözmesini istiyorum.

Benim kodum Fabrika Bağımlılık Enjeksiyon yapısı:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

Şimdi ikisinden de faydalanıyorum. Kodum, sınıf oluşturulduğunda her nesnenin kullanılabilir olduğunu söyleyen Yapıcı Bağımlılık Enjeksiyonu yerine kullandığım nesnelerimin kapsamlarına göre diğer geliştiriciler için daha okunabilir.

Birim Testleri oluştururken Veritabanı Veri Erişimimi özel kodlanmış Veri Erişimi katmanına değiştirmek için bunu kullanıyorum. Birim Testlerimin veritabanları, web sunucuları, e-posta sunucuları vb. İle iletişim kurmasını istemiyorum. İş Katmanımı test etmeleri gerekiyor çünkü zeka burada.


-4

Bağımlılık enjeksiyonunu kullanmak benim görüşüme göre çok daha iyidir: 1. kodunuzu küçük bir bölümde dağıtmak, çünkü büyük bir kodun ayrıştırılmasında iyi işlemektedir. 2. test edilebilirlik DI ayrılmaz nesneleri kolayca alay çünkü DI kullanmak için ok durumda biridir. arayüzlerin kullanımı ile her nesneyi kolayca alay edebilir ve test edebilirsiniz. 3. Programın her bir parçasını, gevşek bir şekilde ayrıştırıldığından, diğer bölümünü kodlamaya gerek kalmadan aynı anda revize edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.