Bağımlılık enjeksiyonunu anlama


109

Bağımlılık enjeksiyonunu (DI) okuyorum . Bana göre, bunu yapmak çok karmaşık bir şeydi, okuduğum için kontrolün tersine çevrilmesi (IoC) de vardı ve böyle bir seyahate çıkacağımı hissettim.

Bu benim anlayışım: Sınıfta onu tüketen bir model oluşturmak yerine, modeli (zaten ilginç özelliklerle dolu olan) ihtiyaç duyulan yere (onu parametre olarak alabilecek yeni bir sınıfa) iletirsiniz (enjekte eder) yapıcı).

Bana göre, bu sadece bir argüman geçiyor. Bayan bu konuyu anlamış olmalı mı? Belki daha büyük projelerle daha da belirginleşir?

Benim anlayış DI-değil (sözde kod kullanarak):

public void Start()
{
    MyClass class = new MyClass();
}

...

public MyClass()
{
    this.MyInterface = new MyInterface(); 
}

Ve DI olur

public void Start()
{
    MyInterface myInterface = new MyInterface();
    MyClass class = new MyClass(myInterface);
}

...

public MyClass(MyInterface myInterface)
{
    this.MyInterface = myInterface; 
}

Biri biraz ışık tutabilir çünkü burada bir karmaşa içindeyim.


5
5 MyInterface ve MyClass AND olan bir bağımlılık zinciri oluşturan birden fazla sınıfa sahip olmayı deneyin. Her şeyi ayarlamak popoda bir acıya dönüşür.
Öforik

159
Bana göre, bu sadece bir argüman geçiyor. Meseleyi yanlış anlamış olmalıyım? ” Hayır. Anladın. Bu "bağımlılık enjeksiyonu". Şimdi basit kavramlar için hangi çılgın jargonu bulabileceğinizi görün, bu eğlenceli!
Eric Lippert

8
Bay Lippert'in yorumunu yeterince oylayamıyorum. Ben de yine de doğal olarak yaptığım bir şey için jargonun kafasını karıştırdığını buldum.
Alex Humphrey

16
@EricLippert: Doğru olsa da, bunun biraz indirgeyici olduğunu düşünüyorum. DI-parametreleri, etrafta veri iletmek için kullanılan ortalama zorunlu / OO programcınız için hemen basit bir kavram değildir. DI burada, vasat bir programcının sahip olacağından daha esnek bir dünya görüşü gerektiren davranışları aşmanıza izin veriyor .
Phoshi

14
@ Phoshi: İyi bir noktaya değindin, ama aynı zamanda "bağımlılık enjeksiyonunun" her şeyden önce iyi bir fikir olduğu konusunda neden şüpheci olduğumu da işaret ediyorsun. Doğruluğuna ve performansına bağlı olarak başka bir sınıfın davranışına bağlı bir sınıf yazarsam , yapmak istediğim son şey, bağımlılığı doğru bir şekilde yapılandırmak ve yapılandırmaktan sınıf kullanıcısını sorumlu yapmaktır! Bu benim işim. Bir tüketiciye bir bağımlılık enjekte etmesine her izin verdiğinizde, tüketicinin yanlış yaptığı bir nokta yaratırsınız.
Eric Lippert

Yanıtlar:


106

Evet, bağımlılıklarınızı ya bir kurucu ya da mülkler aracılığıyla enjekte ediyorsunuz.
Bunun nedenlerinden biri, bir MyInterface örneğinin nasıl inşa edilmesi gerektiğinin ayrıntılarıyla MyClass'ı kuşatmamaktır. MyInterface, bütün bir bağımlılık listesine sahip bir şey olabilir ve MyClass'ın içindeki tüm MyInterface bağımlılıklarını başlattıysanız, MyClass'ın kodu çirkin hale gelirdi.

Diğer bir sebep ise test için.
Bir dosya okuyucu arayüzüne bir bağımlılığınız varsa ve bu bağımlılığa, örneğin ConsumerClass içindeki bir kurucu aracılığıyla enjekte ediyorsanız, bu, test sırasında, dosya okuyucusunun bellek içi bir uygulamasını ConsumerClass'a aktarabilirsiniz. Test sırasında G / Ç yapın.


13
Bu harika, iyi açıklanmış. Temsilcim henüz izin vermediğinden, lütfen hayali bir + 1 kabul edin!
MyDaftQuestions

11
Karmaşık inşaat senaryosu, Fabrika modelinin kullanımı için iyi bir adaydır. Bu şekilde fabrika, nesneyi inşa etme sorumluluğunu üstlenir, böylece sınıfın kendisinin zorunda kalmaması ve tek sorumluluk ilkesine bağlı kalmanız gerekir.
Matt Gibson

1
@ MattGibson iyi bir nokta.
Stefan Billiet

2
Test için +1, iyi yapılandırılmış DI, testin hızlandırılmasına ve test ettiğiniz sınıfta bulunan birim testlerinin yapılmasına yardımcı olacaktır.
Umur Kontacı

52

DI'nin nasıl uygulanabileceği, kullanılan dile çok bağlıdır.

İşte basit bir DI olmayan örnek:

class Foo {
    private Bar bar;
    private Qux qux;

    public Foo() {
        bar = new Bar();
        qux = new Qux();
    }
}

Bu, örneğin bir test için bir sahte nesne kullanmak istediğimde berbat bir durumdur bar. Böylece bunu daha esnek hale getirebilir ve örneklerin kurucu aracılığıyla iletilmesine izin verebiliriz:

class Foo {
    private Bar bar;
    private Qux qux;

    public Foo(Bar bar, Qux qux) {
        this.bar = bar;
        this.qux = qux;
    }
}

// in production:
new Foo(new Bar(), new Qux());
// in test:
new Foo(new BarMock(), new Qux());

Bu zaten bağımlılık enjeksiyonunun en basit şeklidir. Fakat bu hala berbat çünkü her şeyin manuel olarak yapılması gerekiyor (ayrıca, arayan kişi bizim içsel nesnelerimize referans tutabildiği ve böylece durumumuzu geçersiz kıldığı için).

Fabrikaları kullanarak daha fazla soyutlama yapabiliriz:

  • Bir seçenek Foosoyut bir fabrika tarafından üretilmek içindir.

    interface FooFactory {
        public Foo makeFoo();
    }
    
    class ProductionFooFactory implements FooFactory {
        public Foo makeFoo() { return new Foo(new Bar(), new Baz()) }
    }
    
    class TestFooFactory implements FooFactory {
        public Foo makeFoo() { return new Foo(new BarMock(), new Baz()) }
    }
    
    FooFactory fac = ...; // depends on test or production
    Foo foo = fac.makeFoo();
  • Başka bir seçenek de bir fabrikayı kurucuya iletmektir:

    interface DependencyManager {
        public Bar makeBar();
        public Qux makeQux();
    }
    class ProductionDM implements DependencyManager {
        public Bar makeBar() { return new Bar() }
        public Qux makeQux() { return new Qux() }
    }
    class TestDM implements DependencyManager {
        public Bar makeBar() { return new BarMock() }
        public Qux makeQux() { return new Qux() }
    }
    
    class Foo {
        private Bar bar;
        private Qux qux;
    
        public Foo(DependencyManager dm) {
            bar = dm.makeBar();
            qux = dm.makeQux();
        }
    }

Bununla ilgili geriye kalan problemler, DependencyManagerher bir konfigürasyon için yeni bir alt sınıf yazmamız ve yönetilebilecek bağımlılık sayısının oldukça sınırlı olması (her yeni bağımlılığın arayüzde yeni bir yöntem gerektirmesi).

Yansıma ve dinamik sınıf yükleme gibi özelliklerle bunu çözebiliriz. Ancak bu, kullanılan dile çok bağlıdır. Perl'de sınıflar adlarına göre başvuruda bulunabilir ve ben de yapabilirim

package Foo {
    use signatures;

    sub new($class, $dm) {
        return bless {
            bar => $dm->{bar}->new,
            qux => $dm->{qux}->new,
        } => $class;
    }
}

my $prod = { bar => 'My::Bar', qux => 'My::Qux' };
my $test = { bar => 'BarMock', qux => 'QuxMock' };
$test->{bar} = 'OtherBarMock';  # change conf at runtime

my $foo = Foo->new(rand > 0.5 ? $prod : $test);

Java gibi dillerde, bağımlılık yöneticisinin şunlara benzer şekilde davranmasını sağlayabilirim Map<Class, Object>:

Bar bar = dm.make(Bar.class);

Çözülen asıl sınıfa Bar.classçalışma zamanında, örneğin Map<Class, Class>hangisinin uygulamalarla ara yüzleri eşleştirilmesi sağlanarak yapılandırılabilir .

Map<Class, Class> dependencies = ...;

public <T> T make(Class<T> c) throws ... {
    // plus a lot more error checking...
    return dependencies.get(c).newInstance();
}

Yapıcıyı yazmaya dahil olan hala manuel bir unsur var. Ancak yapıcıyı tamamen gereksiz kılabiliriz, örneğin DI'yi ek açıklamalarla sürerek:

class Foo {
    @Inject(Bar.class)
    private Bar bar;

    @Inject(Qux.class)
    private Qux qux;

    ...
}

dm.make(Foo.class);  // takes care of initializing "bar" and "qux"

İşte küçük (ve çok kısıtlı) bir DI çerçevesinin örnek bir uygulaması: http://ideone.com/b2ubuF , bu uygulama değişmez nesneler için tamamen kullanılamaz olmasına rağmen (bu saf uygulama yapıcı için herhangi bir parametre alamaz).


7
Bu harika örneklerle süper, her şeyi sindirmek için bana birkaç kez okumaya devam etse de, çok zaman ayırdığınız için teşekkürler.
MyDaftQuestions

33
Her bir basitleştirmenin daha karmaşık hale
gelmesi

48

Stack Overflow'taki arkadaşlarımız buna güzel bir cevap veriyor . Benim favorim, alıntı dahil ikinci cevap:

"Bağımlılık Enjeksiyonu" 5 kuruş konsepti için 25 dolarlık bir terimdir. (...) Bağımlılık enjeksiyonu, bir nesneye örnek değişkenleri vermek anlamına gelir. (...).

dan James Shore günlüğü . Tabii ki, bunun üzerine yerleştirilmiş daha karmaşık versiyonlar / desenler var, ama neler olduğunu temel olarak anlamak yeterli. Kendi örnek değişkenlerini yaratan bir nesne yerine, dışarıdan iletilir.


10
Bunu okumuştum ... ve şimdiye kadar, hiçbir anlamı yoktu ... Şimdi, mantıklı. Bağımlılık aslında o kadar büyük bir kavram değil (ne kadar güçlü olduğuna bakılmaksızın) ancak büyük bir isim ve bununla ilişkili çok fazla internet gürültüsü var!
MyDaftQuestions

18

Diyelim ki, iç mekan tasarımını oturma odanızda yapıyorsunuz: tavanınıza şık bir avize takıyor ve şık bir zemin lambasına takıyorsunuz. Bir yıl sonra, güzel eşiniz odayı daha az resmi görmek istediğine karar verdi. Hangi aydınlatma armatürünün değiştirilmesi daha kolay olacak?

DI'nin ardındaki fikir her yerde "plug-in" yaklaşımını kullanmaktır . Alçıpan ve açıkta bulunan tüm elektrik telleri ile basit bir kulübe içinde yaşıyorsanız, bu büyük bir sorun gibi görünmeyebilir. (Sen bir tamircisin - her şeyi değiştirebilirsin!) Benzer şekilde, küçük ve basit bir uygulamada DI, değerinden daha fazla komplikasyon ekleyebilir.

Ancak geniş ve karmaşık bir uygulama için DI, uzun süreli bakım için vazgeçilmezdir . Tüm modülleri kodunuzdan (örneğin, veritabanı arka ucu) "çıkarmanıza" ve aynı şeyi yapan ancak tamamen farklı bir şekilde (örneğin bir bulut depolama sistemi) yapan farklı modüllerle değiştirmenize olanak tanır.

BTW, DI'nin tartışması, Mark Seeman tarafından .NET'te Bağımlılık Enjeksiyonunun bir tavsiyesi olmadan tamamlanmış sayılmaz. .NET'e aşina iseniz ve büyük ölçekli SW geliştirmeye dahil olmayı düşünüyorsanız, bu önemli bir okumadır. Konsepti benden çok daha iyi açıklıyor.

Kod örneğinizin göz ardı ettiği DI'nin son temel karakteristiği ile sizi bırakmama izin verin. DI, “ Arayüzler için Program ” atasözünde bulunan geniş esneklik potansiyelinden faydalanmanıza izin verir . Örneğinizi biraz değiştirmek için:

public void Main()
{
    ILightFixture fixture = new ClassyChandelier();
    MyRoom room = new MyRoom (fixture);
}
...
public MyRoom(ILightFixture fixture)
{
    this.MyLightFixture = fixture ; 
}

Ancak ŞİMDİ, MyRoomILightFixture arabirimine göre tasarlandığından , gelecek yıl kolayca gidip Ana işlevdeki bir satırı değiştirebilirim ("farklı bir" bağımlılık "enjekte etmek") ve MyRoom'da yeni işlevsellik elde ediyorum (mecbur kalmadan) ayrı bir kütüphanede olsaydı, MyRoom'u yeniden inşa et ya da yeniden konuşlandır, bu elbette, tüm ILightFixture uygulamalarınızın Liskov Yerine Getirilmesi düşünülerek tasarlandığını varsayar). Hepsi, sadece basit bir değişiklikle:

public void Main()
{
    ILightFixture fixture = new MuchLessFormalLightFixture();
    MyRoom room = new MyRoom (fixture);
}

Artı, şimdi Birim Test edebilir MyRoom(eğer vardır değil mi?, Birim testleri) ve test etmemi sağlayan bir "sahte" ışık fikstür, kullanmak MyRoomtamamen bağımsızClassyChandelier.

Elbette çok daha fazla avantaj var ama bunlar bana fikri satanlar.


Teşekkür etmek istedim, bu bana yardımcı oldu, ama bunu yapmanı istemiyorlar, ancak iyileştirmeler önermek için yorumları kullanmak istiyorlar, bu nedenle, eğer böyle hissederseniz, bahsettiğiniz diğer avantajlardan birini de ekleyebilirsiniz. Ama aksi takdirde, teşekkürler, bu bana yardımcı oldu.
Steve

2
Başvuruda bulunduğunuz kitapla da ilgileniyorum, ancak bu konuda 584 sayfalık bir kitap olduğunu endişe verici buluyorum.
Steve

4

Bağımlılık enjeksiyonu sadece bir parametreyi geçiyor, ancak bu hala bazı sorunlara yol açıyor ve adın bir nesne yaratma ile birini içeri aktarmak arasındaki farkın neden önemli olduğuna biraz odaklanılması amaçlanıyor.

Bu önemlidir, (çok açık bir şekilde) herhangi bir zaman nesnesinin A B türünü çağırdığı zaman, A B'nin nasıl çalıştığına bağlıdır. Bunun anlamı, eğer A hangi somut B türünü kullanacağına karar verirse, o zaman A'nın değiştirilmeden dış sınıflar tarafından A'nın nasıl kullanılacağına dair çok fazla esnekliğin kaybolduğu anlamına gelir.

Bunu söylüyorum, çünkü bağımlılık enjeksiyonunun "eksik noktasını" konuşuyorsunuz ve bu insanların yapmayı neden sevdiği nokta. Sadece bir parametreyi geçmek anlamına gelebilir, ancak bunu yapıp yapmamanız önemli olabilir.

Ayrıca, aslında DI'yi uygulamadaki zorlukların bir kısmı büyük projelerde daha iyi görünmektedir. Genel olarak hangi somut sınıfların en üste kadar kullanılacağına dair gerçek kararı verirsiniz, bu nedenle başlangıç ​​yönteminiz şöyle görünebilir:

public void Start()
{
    MySubSubInterfaceA mySubSubInterfaceA = new mySubSubInterfaceA();
    MySubSubInterfaceB mySubSubInterfaceB = new mySubSubInterfaceB();     
    MySubInterface mySubInterface = new MySubInterface(mySubSubInterfaceA,mySubSubInterfaceB);
    MyInterface myInterface = new MyInterface(MySubInterface);
    MyClass class = new MyClass(myInterface);
}

ancak bu tür perçinleme kodunun başka 400 satırı ile. Bunu zaman içinde sürdürmeyi hayal ediyorsanız, DI konteynerlerinin çekiciliği daha belirgin hale gelir.

Ayrıca, IDisposable uygulayan bir sınıf düşünün. Onu kullanan sınıflar, kendilerini oluşturmak yerine enjeksiyon yoluyla alırlarsa, Dispose () yöntemini ne zaman arayacaklarını nasıl bilirler? (DI konteynerinin ilgilendiği bir başka konudur.)

Dolayısıyla, bağımlılık enjeksiyonu sadece bir parametreyi geçiyor, ancak gerçekten insanlar bağımlılık enjeksiyonunu söylediğinde, "nesnenize bir parametreyi geçirme - nesnenin kendisini somutlaştırması alternatifi" anlamına geliyor ve tüm dezavantajlarının tüm avantajlarını ele alıyorlar. Muhtemelen bir DI konteyneri yardımı ile böyle bir yaklaşım.


Çok fazla sayıda sub ve arayüz var! Arayüzü uygulayan bir sınıf yerine bir arayüz geliştirmek mi istiyorsunuz? Yanlış görünüyor.
JBRWilkinson

@JBRWilkinson Bir arayüz uygulayan bir sınıf demek. Bunu daha netleştirmeliyim. Ancak mesele şu ki, büyük bir uygulamanın sırayla bağımlılıkları olan bağımlılıkları olan bağımlılıkları olan sınıflara sahip olacağı ... Bunların hepsini manuel olarak ayarlamak Ana yöntemde, çok sayıda yapıcı enjeksiyonu yapmanın sonucudur.
psr

4

Sınıf düzeyinde kolaydır.

'Bağımlılık Enjeksiyonu' basitçe "işbirlikçilerimi nasıl bulacağım" sorusunu "sana ittirdikleri - gidip onları kendin almak zorunda değilsin" ile cevaplıyor. ("İşlemlerin girişimi üzerinde nasıl sipariş vereceğim?" Sorusunun benzer bir cevabı olduğu "Kontrolün Tersine Çevirilmesi" ile aynı değildir - aynı değildir).

Sadece sahip ortak çalışanlarınız size aktardığı fayda olduğunu sen keyfi yapmadıysanız özel karar vererek grafiğin şeklini ve değişebilirlik önceden belirlenmiş ... bugünkü gerek uygun bir nesne grafiği oluşturmak için sınıf kullanmak için istemci kodu sağlar İş arkadaşlarınızın somut türleri ve yaşam döngüsü.

(Test edilebilirlik, gevşek bağlanma, vb. Gibi diğer tüm faydalar, DI'nin doğal olarak arayüzlerin kullanımını teşvik etmesine rağmen, büyük ölçüde arayüzlerin kullanımından kaynaklanmaktadır.

Bu nedenle , kendi ortak çalışanlarınızı somutlaştırmaktan kaçınırsanız, sınıfınızın ortak çalışanlarını bir kurucudan, bir mülkten veya bir yöntem argümanından alması gerektiğini belirtmek gerekir (bu ikinci seçenek çoğu zaman göz ardı edilir ... bir sınıfın “ortak çalışanlarının“ devletinin bir parçası olması ”için her zaman mantıklı değil).

Ve bu iyi bir şey.

Uygulama düzeyinde ...

Her şeyi sınıf başına görmek için çok fazla. Diyelim ki "kendi işbirlikçilerinizi somutlaştırmayın" kuralını izleyen ve onlardan bir uygulama yapmak isteyen bir grup dersiniz var. Yapılması gereken en basit şey, istediğiniz nesne grafiğini oluşturmak için eski kodları (yapıcıları, özellikleri ve yöntemleri çağırmak için gerçekten kullanışlı bir araç!) Kullanmak ve ona girdi yazmaktır. (Evet, grafiğinizdeki bu nesnelerin bazıları, grafikteki diğer uzun ömürlü nesnelere ortak çalışanlar olarak görev yapan, servis için hazır olan nesneler-fabrikalar olacaklar ... her nesneyi önceden oluşturamazsınız! ).

... uygulamanızın nesne grafiğini 'esnek bir şekilde' yapılandırmanız gerek ...

Diğer (kodla ilgili olmayan) hedeflerinize bağlı olarak, son kullanıcıya konuşlandırılan nesne grafiği üzerinde bir kontrol hakkı vermek isteyebilirsiniz. Bu, bazı tasarım / isim çiftleri, bir XML dosyası, özel bir DSL, bildirimsel bir grafik-açıklama dili gibi kendi tasarımınızın bir metin dosyası olup olmadığına bakılmaksızın, bir sıralama düzeni veya başka bir yapılandırma şeması yönünde yönlendirir. YAML, JavaScript gibi zorunlu bir betik dili veya eldeki göreve uygun başka bir şey. Kullanıcılarınızın ihtiyaçlarını karşılayacak şekilde geçerli bir nesne grafiği oluşturmak için ne gerekiyorsa.

... önemli bir tasarım gücü olabilir.

Gelen en uç bu tür durum, bir çok genel bir yaklaşım ve son kullanıcılara vermek tercih olabilir genel bir nesne grafiği 'kablolama' için mekanizmayı kendi seçtiği ve hatta izin bunları hiç arayüzleri somut gerçekleşmelerine sağlamak Çalışma süresi! (Belgeleriniz ışıltılı bir mücevherdir, kullanıcılarınız çok zekidir, en azından uygulamanızın nesne grafiğinin kaba taslaklarına aşinadır, ancak bir derleyicinin kullanışlı olması gerekmez). Bu senaryo teorik olarak bazı 'kurumsal' durumlarda ortaya çıkabilir.

Bu durumda, muhtemelen, kullanıcılarınızın herhangi bir türü, bu türden bir nesne grafiğinin kompozisyonunu ve efsanevi son kullanıcının karıştırabileceği ve eşleştirebileceği bir arayüzler paletini ifade etmelerini sağlayan bir bildirim dili vardır. Kullanıcılarınızdaki bilişsel yükü azaltmak için, “konvansiyonel konfigürasyona göre” yaklaşımını tercih edersiniz, böylece ilgilenilen nesne-grafik-fragman parçasına atlamak ve her şeyle uğraşmak yerine sadece üstesinden gelmek zorunda kalırlar.

Seni zavallı sod!

Bunları kendiniz yazmaktan hoşlanmadığınız için (ama cidden, diliniz için bir YAML bağlamasına göz atın), bir tür DI çerçevesi kullanıyorsunuz.

Bu çerçevenin vadesine bağlı olarak, anlamlı olsa bile (ortak çalışanlar bir nesnenin ömrü boyunca değişmez) yapıcı enjeksiyon seçeneğini kullanma şansına sahip olamazsınız; ortak çalışanlar bir nesnenin ömrü boyunca değişmezler ve hatta bir arayüzün tüm somut uygulamalarının belirli bir türden ortak çalışanlara sahip olması gerektiğinin mantıklı bir nedeni olmasa bile ). Öyleyse, kod-temeliniz boyunca korku içinde 'arayüzleri kullanmaya' rağmen, şu anda güçlü bir cehennemdesiniz.

Umarım, size yapıcı enjeksiyon seçeneği sunan bir DI çerçevesi kullandınız ve kullanıcılarınız yapılandırmak için gereken belirli şeyleri düşünmek ve göreve daha uygun bir kullanıcı arayüzü vermek için daha fazla zaman harcamadıkları için size biraz huysuz davranıyorlar . elde. (Adil olmakla birlikte, muhtemelen bir yol düşünmeye çalıştınız, ancak JavaEE sizi hayal kırıklığına uğrattı ve bu korkunç kesmeye başvurmak zorunda kaldı).

Bootnote

Hiçbir zaman Google Guice kullanmıyorsunuz, bu kodlayıcıya kod yazarak kodla bir nesne grafiği oluşturma görevinden vazgeçmenin bir yolunu veriyor. Ahh!


0

Birçok insan burada DI'nin bir örnek değişkenlerin başlatılmasını sağlayan bir mekanizma olduğunu söyledi.

Açık ve basit örnekler için, gerçekten "bağımlılık enjeksiyonuna" ihtiyacınız yoktur. Bunu, belirttiğiniz gibi, kurucuya ileten basit bir parametre ile yapabilirsiniz.

Ancak, hem arayan hem de callee'nin bu kaynaklar hakkında hiçbir şey bilmediği (ve bilmek istemediği) uygulama düzeyinde kaynaklar hakkında konuşurken, özel bir "bağımlılık enjeksiyonu" mekanizmasının yararlı olduğunu düşünüyorum .

Örneğin: Veri tabanı bağlantısı, Güvenlik içeriği, Günlük kaydı tesisi, Yapılandırma dosyası vb.

Ayrıca, genel olarak her singleton DI için iyi bir adaydır. Ne kadarına sahip olursanız ve kullanırsanız, DI'ye ihtiyaç duyduğunuz kadar şansınız olur.

Bu tür kaynaklar için, bunların hepsini parametre listeleri aracılığıyla hareket ettirmenin bir anlamı olmadığı açıkça anlaşılıyor ve bu nedenle DI icat edildi.

Son nota, asıl enjeksiyonu yapacak bir DI kabına da ihtiyacınız var ... (yine hem arayan hem de uygulama detaylarından kaçmak için).


-2

Bir soyut referans tipini iletirseniz, çağıran kod, soyut tipi genişleten / uygulayan herhangi bir nesnede geçebilir. Dolayısıyla gelecekte nesneyi kullanan sınıf, kodunu değiştirmeden yaratılmış yeni bir nesneyi kullanabilirdi.


-4

Amon'un cevabına ek olarak bu başka bir seçenek

Üreticileri kullanın:

sınıf Foo {
    özel Bar bar;
    özel Qux qux;

    özel Foo () {
    }

    genel Foo (Oluşturucu oluşturucu) {
        this.bar = builder.bar;
        this.qux = builder.qux;
    }

    genel statik sınıf oluşturucu {
        özel Bar bar;
        özel Qux qux;
        genel Buider setBar (Bar bar) {
            this.bar = çubuk;
            bunu geri ver;
        }
        genel Oluşturucu setQux (Qux qux) {
            this.qux = qux;
            bunu geri ver;
        }
        Genel Foo build () {
            yeni Foo döndür (bu);
        }
    }
}

// üretimde:
Foo foo = yeni Foo.Builder ()
    .setBar (yeni Bar ())
    .setQux (yeni Qux ())
    .inşa etmek();

// testte:
Foo testFoo = yeni Foo.Builder ()
    .setBar (yeni BarMock ())
    .setQux (yeni Qux ())
    .inşa etmek();

Bağımlılık için kullandığım şey bu. DI çerçeve kullanmıyorum. Yoluna giriyorlar.


4
Bu, bir yıl öncesinden gelen diğer cevaplara fazla bir şey katmaz ve bir inşaatçının neden sorucunun bağımlılık enjeksiyonunu anlamada yardımcı olduğuna dair bir açıklama yapmaz .

@Snowman DI yerine başka bir seçenektir. Üzgünüm, böyle görmüyorsun. Aşağı oy için teşekkürler.
user3155341

1
Soru sahibi DI'nin gerçekten bir parametreyi iletmek kadar basit olup olmadığını anlamak istedi, DI'ye alternatifler istemiyordu.

1
OP örnekleri çok iyi. Örnekleriniz basit bir fikir olan bir şey için daha fazla karmaşıklık sağlar. Sorunun konusunu tasvir etmiyorlar.
Adam Zuckerman

Yapıcı DI bir parametreden geçiyor. Bir somut sınıf nesnesi yerine bir arayüz nesnesini geçiyorsanız. DI ile çözülen somut bir uygulamaya bu 'bağımlılık'. Yapıcı bu tipin nasıl geçtiğini bilmiyor, ne de umurunda değil, sadece bir arayüz uygulayan bir tip aldığını biliyor. PluralSight'ı öneririm, harika bir başlangıç ​​/ DIOC kursu var.
Hardgraf
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.