Bağımlılık enjeksiyonu nedir?


3075

Bağımlılık enjeksiyonu hakkında , ne zaman kullanılacağı ve bunun için hangi çerçevelerin olduğu gibi belirli sorularla birlikte zaten birkaç soru yayınlanmıştır . Ancak,

Bağımlılık enjeksiyonu nedir ve ne zaman / neden kullanılmalı veya kullanılmamalıdır?


Bağımlılık Enjeksiyonu hakkındaki tartışmamı burada görebilirsiniz .
Kevin S.S

33
Bağlantılarla ilgili yorumlara katılıyorum. Başka birine referans vermek isteyebileceğinizi anlayabiliyorum. Ama en azından onları neden bağladığınızı ve bu bağlantıyı google'ı kullanarak alabileceğim diğer bağlantılardan daha iyi yapan şeyleri ekleyin
Christian Payne

@AR: Teknik olarak, Bağımlılık Enjeksiyonu özel bir IoC formu değildir . Aksine, IoC, Bağımlılık Enjeksiyonu sağlamak için kullanılan bir tekniktir. Bağımlılık Enjeksiyonu sağlamak için diğer teknikler kullanılabilir (her ne kadar IoC ortak kullanımda tek olsa da) ve IoC diğer birçok sorun için de kullanılır.
Sean Reilly

DI hakkında şimdiye kadar okuduğum en güzel açıklamalardan biri Google'ın Guice (meyve suyu olarak telaffuz edilir) http://code.google.com/p/google-guice/wiki/Motivation?tm=6
Raj

136
Bağlantılarla ilgili olarak, çoğu zaman bir şekilde yok olduklarını unutmayın. SO cevaplarında giderek artan sayıda ölü bağlantı vardır. Dolayısıyla, bağlantılı makale ne kadar iyi olursa olsun, bulamazsanız hiç de iyi değildir.
DOK

Yanıtlar:


1931

Bağımlılık Enjeksiyonu , diğer nesnelere veya çerçeveye bağımlılığı geçiriyor (bağımlılık enjektörü).

Bağımlılık enjeksiyonu testi kolaylaştırır. Enjeksiyon yapıcı ile yapılabilir .

SomeClass() aşağıdaki gibi yapıcı vardır:

public SomeClass() {
    myObject = Factory.getObject();
}

Sorun : myObjectDisk erişimi veya ağ erişimi gibi karmaşık görevleri içeriyorsa, birim sınaması yapmak zordurSomeClass() . Programcılar alay etmeli myObjectve fabrika çağrısına müdahale edebilirler.

Alternatif çözüm :

  • Yapıcıya myObjectargüman olarak aktarma
public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

myObject doğrudan iletilebilir, bu da testi kolaylaştırır.

  • Yaygın bir alternatif, yap-yap yapıcısının tanımlanmasıdır . Bağımlılık enjeksiyonu ayarlayıcılar aracılığıyla yapılabilir. (h / tMikeVella).
  • Martin Fowler üçüncü bir alternatifi (h / t @MarcDix) belgelemektedir; burada sınıflar , programcıların enjekte etmek istediği bağımlılıklar için açıkça bir arayüz uygulamaktadır .

Bağımlılık enjeksiyonu olmadan birim testindeki bileşenleri izole etmek daha zordur.

2013 yılında, bu yanıtı yazdığımda, bu Google Test Blogunda önemli bir temaydı . Programcılar, çalışma zamanı tasarımlarında her zaman ekstra esnekliğe ihtiyaç duymadıkları için benim için en büyük avantaj olmaya devam ediyor (örneğin, servis bulucu veya benzer desenler için). Programcılar genellikle test sırasında sınıfları izole etmelidir.


25
Ben Hoffstein'ın Martin Fowler'ın makalesine referansının konuyla ilgili 'okunması gereken' bir işaret olarak gerekli olduğunu kabul ederek, wds 'cevabını kabul ediyorum çünkü aslında burada SO ile ilgili soruyu cevaplıyor.
AR.

121
Açıklama ve motivasyon için +1: bir sınıfın başkasının sorununa bağlı olduğu nesnelerin oluşturulmasını sağlamak . Bunu söylemenin başka bir yolu, DI'nin sınıfları daha uyumlu hale getirmesidir (daha az sorumlulukları vardır).
Fuhrmanator

13
Bağımlılığın "kurucuya" iletildiğini söylüyorsunuz ama anladığım kadarıyla bu kesinlikle doğru değil. Bağımlılık nesne başlatıldıktan sonra bir özellik olarak ayarlanırsa, yine bağımlılık enjeksiyonu, değil mi?
Mike Vella

1
@MikeVella Evet, doğru. Çoğu durumda gerçek bir fark yaratmaz, ancak özellikler genellikle biraz daha esnektir. Bunu belirtmek için metni biraz düzenleyeceğim.
wds

2
Şimdiye kadar bulduğum en iyi cevaplardan biri, bu yüzden gerçekten iyileştirmekle ilgileniyorum. Üçüncü bağımlılık enjeksiyonu formunun tanımı eksik: Arayüz enjeksiyonu .
Marc Dix

2351

Şimdiye kadar bulduğum en iyi tanım James Shore'den bir tanesidir :

"Bağımlılık Enjeksiyonu" 5 sentlik bir kavram için 25 dolarlık bir terimdir. [...] Bağımlılık enjeksiyonu, bir nesneye örnek değişkenlerini vermek anlamına gelir. [...].

Martin Fowler tarafından da faydalı olabilecek bir makale var .

Bağımlılık enjeksiyonu temel olarak bir nesnenin kendisini oluşturmak yerine ihtiyaç duyduğu nesneleri (bağımlılıklarını) sağlar. Bağımlılıkların alay edilmesine veya gizlenmesine izin verdiği için test için çok yararlı bir tekniktir.

Bağımlılıklar, nesnelere birçok yolla (yapıcı enjeksiyonu veya ayarlayıcı enjeksiyonu gibi) enjekte edilebilir. Bunu yapmak için özel bağımlılık enjeksiyon çerçeveleri (örneğin Spring) bile kullanılabilir, ancak kesinlikle gerekli değildir. Bağımlılık enjeksiyonuna sahip olmak için bu çerçevelere ihtiyacınız yok. Nesneleri (bağımlılıkları) açıkça örneklemek ve iletmek, çerçeveye göre enjeksiyon kadar iyidir.


35
James'in makalesinin açıklamasını seviyorum, özellikle son: "Yine de, üç kavram ('TripPlanner,' 'CabAgency' 've' AirlineAgency ') alan herhangi bir yaklaşıma hayret etmelisiniz, onları dokuz artı sınıfa dönüştürüyor, ve daha sonra tek bir uygulama mantığı satırı yazılmadan düzinelerce yapıştırıcı kodu ve yapılandırma XML satırı ekler. " Bu çok sık (ne yazık ki) gördüm - bağımlılık enjeksiyon (kendisi tarafından açıklandığı gibi kendiliğinden iyi) daha kolay yapılabilecek şeylerin aşırı karmaşıklaştırmak için yanlış - "destek" kodu yazma sona erdi ...
Matt

2
Ynt: "Nesneleri (bağımlılıkları) açıkça örneklemek ve geçirmek, çerçeveye göre enjeksiyon kadar iyidir." Peki neden insanlar bunu yaparken çerçeveler yaptılar?
dzieciou

13
Her sebeple her çerçevenin yazılması (veya en azından alması gerekir) için aynı sebepten dolayı: belli bir karmaşıklığa ulaştığınızda yazılması gereken çok sayıda tekrarlanan / kaynak kodu vardır. Sorun, herkesin kesinlikle gerekli olmadığında bile bir çerçeveye ulaşmasıdır.
Thiago Arrais

14
5 sentlik bir kavram için 25 dolarlık bir terim öldü. İşte bana yardımcı olan iyi bir makale: codeproject.com/Articles/615139/…
Christine

@ Yapılandırma dosyaları sadece "karar erteleme" aşırı taşınan - "Karar gerçek çalışma zamanı erteleme". Hançer ve özellikle Hançer bence "Kararın uygulama montaj zamanına ertelenmesini" buldular.
Thorbjørn Ravn Andersen

645

Bu eğlenceli örneği gevşek bağlantı açısından buldum :

Herhangi bir uygulama, yararlı şeyler yapmak için birbirleriyle işbirliği yapan birçok nesneden oluşur. Geleneksel olarak her nesne, birlikte çalıştığı bağımlı nesnelere (bağımlılıklara) kendi referanslarını almaktan sorumludur. Bu, yüksek derecede eşleştirilmiş sınıflara ve test edilmesi zor koda yol açar.

Örneğin, bir Carnesneyi düşünün .

A Car, çalıştırmak için tekerleklere, motora, yakıta, aküye vb. Bağlıdır. Geleneksel olarak, bu tür bağımlı nesnelerin markasını, Carnesnenin tanımıyla birlikte tanımlarız .

Bağımlılık Enjeksiyonu Olmadan (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Burada, Carnesne bağımlı nesneleri oluşturmaktan sorumludur.

Wheelİlk NepaliRubberWheel()deliklerden sonra bağımlı nesnesinin türünü (örneğin,) değiştirmek istersek ne olur ? Car nesnesini yeni bağımlılığıyla yeniden yaratmamız gerekiyor ChineseRubberWheel(), ancak bunu sadece Carüretici yapabilir.

O zaman Dependency Injectionbizim için ne yapar ...?

Bağımlılık enjeksiyonu kullanıldığında, nesnelere derleme zamanı (araç üretim zamanı) yerine çalışma zamanında bağımlılıkları verilir . Böylece Wheelistediğimiz zaman değiştirebiliriz . Burada, dependency( wheel) Carçalışma zamanında enjekte edilebilir .

Bağımlılık enjeksiyonunu kullandıktan sonra:

Burada, vardır enjekte bağımlılıkları zamanında (Tekerlek ve Pil). Dolayısıyla terim: Bağımlılık Enjeksiyonu.

class Car{
  private Wheel wh; // Inject an Instance of Wheel (dependency of car) at runtime
  private Battery bt; // Inject an Instance of Battery (dependency of car) at runtime
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Kaynak: Bağımlılık enjeksiyonunu anlama


20
Bunu anlama şeklim, yeni bir nesneyi başka bir nesnenin parçası olarak başlatmak yerine, söz konusu nesneyi gerektiğinde ve gerektiğinde enjekte edebilir ve böylece ilk nesnenin ona bağımlılığını kaldırabiliriz. Bu doğru mu?
JeliBeanMachine

Bunu bir kahve dükkanı örneğiyle burada açıkladım
Ali Nem

11
Gerçekten bu benzetmeyi seviyorum çünkü basit bir benzetme kullanarak sade İngilizce. Saygın lastik üreticilerini mevcut olup olmadığını, neden bir lastik imalatı bölümü yani yapmak için sıfırdan başlamalı Ben, satır birleştirin yuvarlanmasını tasarımdan bir araba yapmaya çok fazla maddi geçirdi ve insan gücü zaten Toyota olduğumu söyle newbir tekerlek? Yapmıyorum. Tek yapmam gereken onlardan satın almak (param yoluyla enjekte etmek), kurmak ve wah-lah! Yani, programlamaya geri dönersek, bir C # projesinin mevcut bir kütüphane / sınıfı kullanması gerektiğini söyleyin, bunun tüm projeye 1-add referansı için iki yol vardır
Jeb50

(con't), .. harici kitaplık / sınıf veya DLL'den 2-ekleyin. Bu dış sınıfın içindekileri görmemiz gerekmedikçe, DLL olarak eklemek daha kolay bir yoldur. Yani seçenek 1 newona, seçenek 2 ise param olarak iletilir. Doğru olmayabilir, ancak basit aptal kolay anlaşılır.
Jeb50

1
@JeliBeanMachine (bir yoruma son derece geç cevap verdiğim için özür dilerim ..) ilk nesnenin tekerlek nesnesine veya pil nesnesine bağımlılığını kaldırmamız değil, bağımlılığı geçirebilmemiz, böylece uygulamanın örneğini veya uygulamasını değiştirebilmemiz bağımlılık. Önceki: Otomobilin NepaliRubberWheel'a kodlanmış bir bağımlılığı var. Sonra: Otomobilin Tekerlek örneğine bağımlı bir bağımlılığı vardır.
Mikael Ohlson

263

Bağımlılık Enjeksiyonu, nesnelerin dahili olarak inşa etmek yerine, nesnelerin diğer kod parçalarından örneklerini alacakları şekilde tasarlandığı bir uygulamadır. Bu, nesnenin gerektirdiği arabirimi uygulayan herhangi bir nesnenin, kodu değiştirmeden, sınamayı basitleştiren ve ayırmayı geliştiren yerine kullanılabileceği anlamına gelir.

Örneğin, şu sınıfları düşünün:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

Bu örnekte, uygulanması PersonService::addManagerve PersonService::removeManagerbir örneğini gerekir GroupMembershipServiceişini yapmak için. Bağımlılık Enjeksiyonu olmadan, bunu yapmanın geleneksel yolu, bu örnek niteliğini her iki işlevde de yeni bir örnek GroupMembershipServiceoluşturmak PersonServiceve kullanmaktır. Yapıcısı Ancak, GroupMembershipServicehenüz çoklu gerektiriyorsa şeyler, ya da daha kötüsü vardır, ihtiyaç üzerine çağrılacak bazı başlatma "belirleyiciler" vardır GroupMembershipService, kod oldukça hızlı büyür ve PersonServiceşimdi de bağlıdır GroupMembershipServiceama aynı zamanda her şey o GroupMembershipServicebağlıdır. Ayrıca, bağlantı GroupMembershipService, içine PersonService"kukla" alamayacağınız anlamına gelir.GroupMembershipService test amacıyla veya uygulamanızın farklı bölümlerinde bir strateji modeli kullanmak için.

Dependency Injection ile, yerine nesnelleştirilme GroupMembershipServiceSİZİN içinde PersonService, ya kadar içeri geçerdi PersonServiceyapıcı, ya da başka onun bir yerel örneğini ayarlamak için bir özellik (alıcı ve ayarlayıcı) ekleyin. Bu, PersonServiceartık nasıl oluşturulacağı konusunda endişelenmenize gerek olmadığı anlamına gelir, GroupMembershipServicesadece verilenleri kabul eder ve onlarla çalışır. Bu aynı zamanda bir alt sınıfıdır bunun bir anlamı GroupMembershipServiceveya aletlerin GroupMembershipServicearayüzü içine "enjekte" olabilir PersonServiceve PersonServicedeğişim hakkında bilmek gerekmez.


29

170

Kabul edilen cevap iyi bir cevaptır - ancak buna DI'nin koddaki sabit kodlu sabitlerden kaçınmanın klasikine çok benzediğini eklemek isterim.

Veritabanı adı gibi bir sabit kullandığınızda, bunu kodun içinden hızlı bir şekilde bir yapılandırma dosyasına taşır ve bu değeri içeren bir değişkeni gereken yere geçirirsiniz. Bunu yapmanın nedeni, bu sabitlerin genellikle kodun geri kalanından daha sık değişmesidir. Örneğin, kodu bir test veritabanında test etmek isterseniz.

DI, Nesne Tabanlı programlama dünyasında buna benzer. Sabit değişmez değerler yerine oradaki değerler tüm nesnelerdir - ancak bunları oluşturan kodu sınıf kodundan çıkarmanın nedeni benzerdir - nesneler bunları kullanan koddan daha sık değişir. Böyle bir değişikliğin gerekli olduğu önemli bir durum testlerdir.


18
+1 "nesneler, bunları kullanan koddan daha sık değişir". Genelleştirmek için, akı noktalarına bir dolaylı yol ekleyin. Akı noktasına bağlı olarak, indirimler farklı isimlerle çağrılır !!
Chethan

139

Araba ve Motor sınıflarıyla basit bir örnek deneyelim , herhangi bir araba en azından şimdilik herhangi bir yere gitmek için bir motora ihtiyaç duyar. Kod aşağıda bağımlılık enjeksiyonu olmadan nasıl görüneceğini aşağıda.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

Ve Car sınıfını başlatmak için bir sonraki kodu kullanacağız:

Car car = new Car();

GasEngine ile sıkı bir şekilde eşleştirdiğimiz bu koddaki sorun ve bunu ElectricityEngine olarak değiştirmeye karar verirsek, Araba sınıfını yeniden yazmamız gerekecek. Ve uygulama büyüdükçe daha fazla sorun ve baş ağrısı, yeni tip motor eklemek ve kullanmak zorunda kalacağız.

Başka bir deyişle, bu yaklaşımla yüksek seviye Araba sınıfımız, SOLID'den Bağımlılık Ters Çevirme İlkesini (DIP) ihlal eden alt seviye GasEngine sınıfına bağımlıdır. DIP, somut sınıflara değil, soyutlamalara güvenmemiz gerektiğini önermektedir. Yani bunu karşılamak için IEngine arayüzü tanıtmak ve aşağıdaki gibi kodu yeniden yazmak:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Şimdi Car sınıfımız motorun belirli bir uygulamasına değil, sadece IEngine arayüzüne bağımlıdır. Şimdi, işin tek yolu, bir Otomobil örneğini nasıl oluşturacağımız ve ona GasEngine veya ElectricityEngine gibi gerçek bir beton Motor sınıfı nasıl vereceğimizdir. İşte bu noktada Bağımlılık Enjeksiyonu devreye giriyor.

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Burada temel olarak bağımlılığımızı (Motor örneği) Araba yapıcısına enjekte ediyoruz (geçiriyoruz). Yani şimdi sınıflarımız nesneler ve bağımlılıkları arasında gevşek bir bağlantıya sahipler ve Car sınıfını değiştirmeden yeni motor türlerini kolayca ekleyebiliriz.

Bağımlılık Enjeksiyonunun ana yararı, sınıfların daha gevşek bağlanmasıdır, çünkü sabit kodlanmış bağımlılıkları yoktur. Bu, yukarıda bahsedilen Bağımlılık Tersine Çevirme İlkesini izler. Belirli uygulamalara başvurmak yerine, sınıflar , sınıf inşa edildiğinde kendilerine sağlanan soyutlamaları (genellikle arabirimler ) ister.

Sonuçta, Bağımlılık enjeksiyonu sadece nesneler ve bağımlılıkları arasında gevşek bir bağlantı elde etmek için bir tekniktir. Sınıfın eylemlerini gerçekleştirmek için ihtiyaç duyduğu doğrudan bağımlılıkları somutlaştırmak yerine, kurucu enjeksiyon yoluyla sınıfa (en sık) bağımlılıklar sağlanır.

Ayrıca birçok bağımlılığımız olduğunda, tüm bağımlılıklarımız için hangi arayüzlerin hangi somut uygulamalarla eşleştirilmesi gerektiğini söyleyebileceğimiz İnversiyon Kontrol (IoC) konteynerlerini kullanmak çok iyi bir uygulamadır ve bu bağımlılıkları inşa ettiğimizde bizim için bu bağımlılıkları çözmesini sağlayabiliriz. bizim amacımız. Örneğin, bu IoC kapsayıcı için eşlemenizde belirtebilirsiniz IEngine bağımlılık aktarılması gerektiğini GasEngine sınıf ve bizim bir örneği için IoC kapsayıcı sorduğunuzda Araba sınıfının, otomatik bizim inşa edecek Araba bir ile sınıf GasEngine bağımlılık geçti.

GÜNCELLEME: Son zamanlarda Julie Lerman'dan EF Core hakkında kurs izledi ve DI hakkındaki kısa tanımını beğendi.

Bağımlılık enjeksiyonu, uygulamanızın, bu sınıflardan bu nesnelerden sorumlu olmaya zorlamadan, gereksinim duyan sınıflara nesneleri anında enjekte etmesini sağlayan bir modeldir. Kodunuzun daha gevşek bir şekilde bağlanmasını sağlar ve Entity Framework Core aynı hizmet sistemine bağlanır.


2
sadece meraktan, bunun strateji modelinden farkı nedir? Bu örüntü algoritmaları kapsüllemekte ve bunları değiştirilebilir kılmaktadır. Bağımlılık enjeksiyonu gibi görünüyor ve strateji kalıpları çok benzer.
iksir

110

Balığa gitmek istediğinizi düşünelim:

  • Bağımlılık enjeksiyonu olmadan, her şeye kendiniz bakmanız gerekir. Bir tekne bulmanız, bir olta satın almanız, yem araması vb. İçin ihtiyacınız var. Yazılım terimleriyle, bu şeyler için bir arama yapmanız gerektiği anlamına gelir.

  • Bağımlılık enjeksiyonu ile, başka bir kişi tüm hazırlığı yapar ve gerekli ekipmanı sizin için kullanılabilir hale getirir. Tekneyi, oltayı ve yemi alırsınız ("enjekte edilir") - hepsi kullanıma hazırdır.


59
Flipside, banyonuzu yeniden yapmak için bir tesisatçı tuttuğunuzu hayal edin, o zaman "Harika, işte benim için almam gereken araçların ve malzemelerin listesi" diyor. Tesisatçının işi bu olmamalı mı?
jscs

Birisinin bilmediği bir işi olmayan biriyle ilgilenmesi için .. ama yine de kullanıma hazır olsa da tekne, sopa ve yem listesini toplamaya karar verir.
Chookoos

22
@JoshCaswell Hayır, bu tesisatçının görevlisinin işi. Bir müşteri olarak sıhhi tesisat yapılması gerekir. Bunun için bir tesisatçıya ihtiyacınız var. Tesisatçının aletlerine ihtiyacı var. Bunları almak için, sıhhi tesisat şirketi tarafından donatılmıştır. Müşteri olarak tesisatçının ne yaptığını veya neye ihtiyacı olduğunu tam olarak bilmek istemezsiniz. Bir tesisatçı olarak neye ihtiyacınız olduğunu biliyorsunuz, ama sadece işinizi yapmak istiyorsunuz, her şeyi elde etmiyorsunuz. Tesisatçı işveren olarak, tesisatçılarınızı insanların evlerine göndermeden önce ihtiyaç duydukları şeylerle donatmaktan sorumlusunuz.
sara

@kai Ne demek istediğini anlıyorum. Yazılımda bir fabrikadan bahsediyoruz, değil mi? Ancak DI, genellikle, sınıfın hala enjekte edilmediği için bir fabrika kullanmadığı anlamına gelir. Müşteri olarak sizlere aletleri vermek için işveren (fabrika) ile görüşmeniz gerekir, böylece tesisatçıya geçebilirsiniz. Aslında bir programda böyle olmaz mı? Bu nedenle, müşteri (sınıfı / işlevi / her ne olursa olsun) araçları temin etmek zorunda kalmasa da, hala işveren (fabrika) tesisatçıya (enjekte edilen sınıf) yaptıklarından emin olmak için orta insan olmak zorundalar.
KingOfAllTrades

1
@KingOfAllTrades: Tabii bir noktada tesisatçı istihdam eden ve teçhizat eden birine sahip olmanız veya tesisatçınız yok. Ama müşteriniz bunu yapmıyor. Müşteri sadece bir tesisatçı ister ve bir işini yapmak için ihtiyaç duyduğu şeyle donatılır. DI ile, yine de bağımlılıkları yerine getirmek için bazı kodlarınız var. Ama gerçek iş yapan koddan ayırıyorsunuz. Bunu sonuna kadar alırsanız, nesneleriniz bağımlılıklarını bilinir hale getirir ve nesne-grafik oluşturma dışarıda, genellikle init kodunda olur.
cHao

102

Bu şimdiye kadar gördüğüm Bağımlılık Enjeksiyonu ve Bağımlılık Enjeksiyon Kabı hakkında en basit açıklama :

Bağımlılık Enjeksiyonu Olmadan

  • Uygulama Foo'ya (örneğin bir kontrolör) ihtiyaç duyar, bu nedenle:
  • Uygulama Foo oluşturur
  • Uygulama çağrıları Foo
    • Foo'nun Bar'a (örneğin bir hizmete) ihtiyacı vardır, yani:
    • Foo Bar oluşturuyor
    • Foo Bar'ı çağırır
      • Bar'ın Bim'e (bir hizmet, bir depo,…) ihtiyacı var, yani:
      • Bar Bim'i yaratıyor
      • Bar bir şey yapar

Bağımlılık Enjeksiyonu ile

  • Uygulama, Bim'e ihtiyaç duyan Bar'a ihtiyaç duyan Foo'ya ihtiyaç duyar, bu yüzden:
  • Uygulama Bim oluşturur
  • Uygulama Bar oluşturur ve Bim verir
  • Uygulama Foo oluşturur ve Bar verir
  • Uygulama çağrıları Foo
    • Foo Bar'ı çağırır
      • Bar bir şey yapar

Bağımlılık Enjeksiyon Kabı Kullanma

  • Uygulama Foo yani:
  • Uygulama Foo Konteyner alır, bu yüzden:
    • Konteyner Bim'i oluşturur
    • Konteyner Bar oluşturur ve Bim verir
    • Konteyner Foo oluşturur ve Bar verir
  • Uygulama çağrıları Foo
    • Foo Bar'ı çağırır
      • Bar bir şey yapar

Bağımlılık Enjeksiyonu ve bağımlılık Enjeksiyon Kapları farklı şeylerdir:

  • Bağımlılık Enjeksiyonu daha iyi kod yazma yöntemidir
  • DI Konteyner bağımlılıkların enjekte edilmesine yardımcı olan bir araçtır

Bağımlılık enjeksiyonu yapmak için bir kaba ihtiyacınız yoktur. Ancak bir konteyner size yardımcı olabilir.



55

"Bağımlılık enjeksiyonu" sadece parametreleştirilmiş kurucuları ve kamu ayarlayıcılarını kullanmak anlamına gelmiyor mu?

James Shore'nin makalesi karşılaştırma için aşağıdaki örnekleri göstermektedir .

Bağımlılık enjeksiyonu olmayan yapıcı:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Bağımlılık enjeksiyonlu yapıcı:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}

Kesinlikle DI sürümünde, hiçbir argüman yapıcısında myDatabase nesnesini başlatmak istemez misiniz? Hiçbir anlamı yok ve aşırı yükleyici yapıcı çağırmadan DoStuff'ı çağırmaya çalışırsanız bir istisna atmak için hizmet eder?
Matt Wilko

Yalnızca new DatabaseThingie()geçerli bir myDatabase örneği oluşturmazsa.
JaneGoodall

40

Bağımlılık Enjeksiyonu kavramının anlaşılmasını kolaylaştırmak. Bir ampulü değiştirmek (açmak / kapatmak) için anahtar düğmesine bir örnek verelim.

Bağımlılık Enjeksiyonu Olmadan

Anahtarın önceden hangi ampule bağlı olduğumu bilmesi gerekir (sabit kodlu bağımlılık). Yani,

Switch -> PermanentBulb // switch doğrudan kalıcı ampule bağlı, test kolayca mümkün değil

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Bağımlılık Enjeksiyonu ile

Switch yalnızca, hangi Ampul bana geçtiğinde açıp kapatmam gerektiğini biliyor. Yani,

Anahtar -> Ampul1 VEYA Ampul2 VEYA Gece Ampulü (enjekte bağımlılık)

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

Anahtar ve Ampul için James Örneğini Değiştirme :

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`

36

Bağımlılık Enjeksiyonu (DI) nedir?

Diğerlerinin söylediği gibi, Bağımlılık Enjeksiyonu (DI) , ilgi sınıfımızın (tüketici sınıfı) bağımlı olduğu diğer nesne örneklerinin ( UML anlamında ) doğrudan yaratılması ve ömrünün yönetilmesi sorumluluğunu ortadan kaldırır . Bu örnekler bunun yerine, tipik olarak yapıcı parametreleri olarak veya özellik ayarlayıcıları aracılığıyla tüketici sınıfımıza iletilir (tüketici nesnesinin başlatılması ve tüketici sınıfına geçirilmesi bağımlılığı yönetimi genellikle bir Denetimi Ters Çevirme (IoC) tarafından gerçekleştirilir kapsayıcısı , ancak bu başka bir konudur) .

DI, DIP ve KATI

Özellikle, Robert C Martin'in paradigma Tasarım Odaklı Nesne KATI ilkelerine , DIolası uygulamalarından biridir Bağımlılık Inversion İlke (DIP) . DIP olduğu Dbir SOLIDmantra diğer DIP uygulamaları Servis Locator ve Eklenti desenleri - bulunur.

DIP amacı ise, bir ile elde edilebilir bir soyutlama vasıtasıyla bağlanması gevşetmek için, bunun yerine, sıkı ayrıştırarak sınıflar arasında somut bağımlılıklar ve etmek interface, abstract classya dapure virtual class kullanılan dil ve yaklaşım bağlı olarak.

DIP olmadan, kodumuz (bu 'tüketen sınıf' olarak adlandırdım) doğrudan somut bir bağımlılığa bağlıdır ve aynı zamanda bu bağımlılığın bir örneğini nasıl elde edeceğini ve yöneteceğini bilme sorumluluğuyla, yani kavramsal olarak:

"I need to create/use a Foo and invoke method `GetBar()`"

DIP'nin uygulanmasından sonra gereksinim gevşetilir ve Foobağımlılığın ömrünü elde etme ve yönetme endişesi ortadan kaldırılır:

"I need to invoke something which offers `GetBar()`"

Neden DIP (ve DI) kullanıyorsunuz?

Sınıflar arasındaki bağımlılıkları bu şekilde ayırmak , bu bağımlılık sınıflarının soyutlamanın önkoşullarını da yerine getiren diğer uygulamalarla kolayca değiştirilmesine izin verir (örneğin, bağımlılık aynı arayüzün başka bir uygulamasıyla değiştirilebilir). Ayrıca, diğerleri de gibi, olasılıkla DIP yoluyla Decouple sınıflarına en yaygın nedeni bir tüketen sınıf bu aynı bağımlılıklar artık stubbed edilebileceği gibi, izolasyon test edilmiş ve / veya alay edilecek sağlamaktır.

DI'nin bir sonucu, bağımlılık nesnesi örneklerinin ömür boyu yönetiminin artık bağımlılık nesnesi artık tüketen sınıfa aktarıldığı için (yapıcı veya ayarlayıcı enjeksiyonu yoluyla) tüketen bir sınıf tarafından kontrol edilmemesidir.

Bu farklı şekillerde görüntülenebilir:

  • Tüketici sınıfı tarafından bağımlılıkların ömür boyu kontrolünün korunması gerekiyorsa, bağımlılık sınıfı örnekleri oluşturmak için (soyut) bir fabrika tüketici sınıfına enjekte edilerek kontrol yeniden oluşturulabilir. Tüketici, gerektiğinde Createfabrikada bir üzerinden örnek alabilecek ve bu örnekleri tamamlandığında imha edebilecektir .
  • Veya, bağımlılık örneklerinin ömür boyu kontrolü bir IoC kapsayıcısından ayrılabilir (bunun hakkında daha fazla bilgi aşağıdadır).

DI ne zaman kullanılır?

  • Eşdeğer bir uygulama için bir bağımlılığın yerine geçmesi gerektiğinde,
  • Bir sınıfın yöntemlerini bağımlılıklarını izole ederek birim olarak test etmeniz gerektiğinde,
  • Bir bağımlılığın yaşam süresinin belirsizliğinin denemeyi gerektirdiği durumlarda (örneğin Hey, MyDepClassiş parçacığı güvenlidir - ya bir tekton yaparsak ve aynı örneği tüm tüketicilere enjekte edersek?)

Misal

İşte basit bir C # uygulaması. Aşağıdaki Tüketici sınıfı göz önüne alındığında:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Görünüşte zararsız olsa da, staticdiğer iki sınıfa iki bağımlılığı vardır System.DateTimeve System.Consolebu sadece günlük çıktı seçeneklerini sınırlamakla kalmaz (hiç kimse izlemiyorsa konsola giriş yapmak değersiz olacaktır), ancak daha da kötüsü, bağımlılık göz önüne alındığında otomatik olarak test edilmesi zordur. deterministik olmayan bir sistem saati.

Bununla birlikte DIP, zaman damgasının bir bağımlılık olarak kaygısını ortadan kaldırarak ve MyLoggersadece basit bir arayüzle eşleştirerek bu sınıfa başvurabiliriz :

public interface IClock
{
    DateTime Now { get; }
}

Ayrıca Consolebir soyutlamaya olan bağımlılığı gevşetebiliriz TextWriter. Bağımlılık Enjeksiyonu tipik olarak constructorenjeksiyon (bir tüketen sınıfın yapıcısına bir parametre olarak bağımlılığa bir soyutlama geçirerek) veya Setter Injection(bağımlılığı bir setXyz()ayarlayıcı veya {set;}tanımlanmış bir .Net Özelliği aracılığıyla geçirerek ) olarak uygulanır. Konstrüktör Enjeksiyonu tercih edilir, çünkü bu, inşaattan sonra sınıfın doğru durumda olacağını garanti eder ve iç bağımlılık alanlarının readonly(C #) veya final(Java) olarak işaretlenmesine izin verir . Yukarıdaki örnekte yapıcı enjeksiyonu kullanarak, bu bize aşağıdakileri bırakır:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

( ClockElbette geri dönebilecek bir betonun sağlanması DateTime.Nowve iki bağımlılığın yapıcı enjeksiyonu yoluyla bir IoC konteyneri tarafından sağlanması gerekir)

Artık bağımlılıklar üzerinde zamana sahip olduğumuzdan ve yazılı çıktıyı gözetleyebileceğimizden, günlükçümüzün doğru çalıştığını kesin olarak kanıtlayan otomatik bir Birim Testi oluşturulabilir:

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Sonraki adımlar

Bağımlılık enjeksiyonu, değişmez bir şekilde bir Inversion of Control konteyneri (IoC) ile , somut bağımlılık örneklerini enjekte etmek (sağlamak) ve kullanım ömrü örneklerini yönetmek için ilişkilendirilir. Yapılandırma / önyükleme işlemi sırasında IoCkaplar aşağıdakilerin tanımlanmasına izin verir:

  • her soyutlama ile yapılandırılmış somut uygulama arasında eşleme (ör. "bir tüketici her talep ettiğinde IBar, bir ConcreteBarörnek döndür" )
  • her bağımlılığın ömür boyu yönetimi için politikalar oluşturulabilir, örneğin her tüketici örneği için yeni bir nesne oluşturmak, tek bir bağımlılık örneğini tüm tüketiciler arasında paylaşmak, aynı bağımlılık örneğini yalnızca aynı iş parçacığında paylaşmak vb.
  • .Net'te IoC kapsayıcıları , yapılandırılmış kullanım ömrü yönetimi doğrultusunda bağımlılıkların IDisposablesorumluluğunun bilincindedir ve bunlardan sorumlu olacaktır Disposing.

Tipik olarak, IoC kapları yapılandırıldıktan / önyükleme yapıldıktan sonra arka planda sorunsuz bir şekilde çalışırlar, kodlayıcının bağımlılıklar hakkında endişelenmek yerine eldeki koda odaklanmasını sağlarlar.

DI-dostu kodun anahtarı, sınıfların statik olarak birleştirilmesinden kaçınmak ve Bağımlılıklar oluşturmak için new () kullanmamaktır

Yukarıdaki örneğe göre, bağımlılıkların ayrıştırılması bazı tasarım çabaları gerektirir ve geliştirici için, newbağımlılıkları doğrudan kullanma alışkanlığını kırmak ve bunun yerine bağımlılıkları yönetmek için kaba güvenmek için gerekli bir paradigma değişimi vardır .

Ancak, özellikle ilgi sınıfınızı kapsamlı bir şekilde test etme yeteneğinde faydalar çoktur.

Not : new ..()POCO / POJO / Serileştirme DTO'ları / Varlık Grafikleri / Anonim JSON projeksiyonları ve diğerlerinin oluşturulması / eşleştirilmesi / projeksiyonu (yoluyla ) - yani yöntemlerden kullanılan veya döndürülen "yalnızca veri" sınıfları veya kayıtları Bağımlılıklar olarak kabul edilmez ( UML anlamda) ve DI'ye tabi değildir. newBunları yansıtmak için kullanmak gayet iyi.


1
Sorun DIP! = DI. DIP, soyutlamanın uygulamadan ayrıştırılması ile ilgilidir: A. Yüksek seviyeli modüller, düşük seviyeli modüllere bağlı olmamalıdır. Her ikisi de soyutlamalara bağlı olmalıdır. B. Soyutlamalar detaylara bağlı olmamalıdır. Ayrıntılar soyutlamalara bağlı olmalıdır. DI, nesne oluşturmayı nesne kullanımından ayırmanın bir yoludur.
Ricardo Rivaldo

Evet, ayrım, Bob Amca'nın SOLID paradigmasında , 2. paragrafım olan "DIP'nin olası uygulamalarından biri" bölümünde açıkça belirtilmiştir . Bunu daha önceki bir yazıda da açıkladım .
StuartLC

25

Bağımlılık Enjeksiyonunun (DI) tüm amacı uygulama kaynak kodunu temiz ve kararlı tutmaktır :

  • bağımlılık temiz başlatma kodu
  • kullanılan bağımlılığa bakılmaksızın kararlı

Pratik olarak, her tasarım deseni gelecekteki değişikliklerin minimum dosyaları etkilemesi için endişeleri ayırır.

DI'nin spesifik alanı bağımlılık konfigürasyonu ve başlatmanın devredilmesidir.

Örnek: DI kabuk kabuklu

Zaman zaman Java dışında çalışıyorsanız source, birçok komut dosyası dilinde (Shell, Tcl, vb.) Ve hatta importbu amaçla yanlış kullanılan Python'da nasıl kullanıldığını hatırlayın .

Basit dependent.shkomut dosyasını düşünün :

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Komut dosyası bağımlıdır: kendi kendine başarıyla yürütülmez ( archive_filestanımlanmamıştır).

Sen tanımlamak archive_filesiçinde archive_files_zip.sh(kullanarak uygulama komut zipbu durumda):

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "$@"
}

sourceDoğrudan bağımlı olanda uygulama betiğini kullanmak yerine, injector.shher iki "bileşeni" de saran bir "kapsayıcı" kullanırsınız :

#!/bin/sh 
# Injector
source ./archive_files_zip.sh
source ./dependent.sh

archive_files Bağımlılık sadece edilmiş enjekte içine bağımlı senaryo.

Sen uygular bağımlılık enjekte olabilirdi archive_fileskullanarak tarveya xz.

Örnek: DI'yi kaldırma

Eğer dependent.shkomut doğrudan bağımlılıkları kullanılan yaklaşım aranmak bağımlılık araması (tersidir bağımlılık enjeksiyon ):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Şimdi sorun bağımlı "bileşen" başlatmanın kendisini gerçekleştirmek zorunda olmasıdır.

"Bileşen" in kaynak kodu ne temiz ne de kararlıdır, çünkü bağımlılıkların başlatılmasındaki her değişiklik "bileşenlerin" kaynak kod dosyası için de yeni sürüm gerektirir.

Son sözler

DI, Java çerçevelerinde olduğu gibi büyük ölçüde vurgulanmaz ve popülerleştirilmez.

Ancak, endişeleri bölmek için genel bir yaklaşım:

  • uygulama geliştirme ( tek kaynak kodlu sürüm yaşam döngüsü)
  • uygulama dağıtımı ( çoklu bağımsız yaşam döngülerine sahip hedef ortam)

Yapılandırmayı yalnızca bağımlılık aramasıyla kullanmak yardımcı olmaz çünkü yapılandırma parametrelerinin sayısı bağımlılık başına değişebilir (örn. Yeni kimlik doğrulama türü) ve desteklenen bağımlılık türlerinin sayısı (örn. Yeni veritabanı türü).


DI için bir amaç olarak, bağımlılıklarını tamamlamak zorunda kalmadan belirli bir sınıfı (test) tamamlama yeteneğini eklerdim.
David

22

Yukarıdaki tüm cevaplar iyidir, amacım kavramı basit bir şekilde açıklamaktır, böylece programlama bilgisi olmayan herkes de kavramı anlayabilir

Bağımlılık enjeksiyonu, karmaşık sistemleri daha basit bir şekilde oluşturmamıza yardımcı olan tasarım modellerinden biridir.

Bu modelin günlük yaşamımızda çok çeşitli uygulamalarını görebiliriz. Bazı örnekler teyp, VCD, CD Sürücü vb.

Makaradan makaraya taşınabilir teyp, 20. yüzyılın ortalarında.

Yukarıdaki görüntü, 20. yüzyılın ortalarında, makaradan makaraya taşınabilir teyp kaydedicinin bir görüntüsüdür. Kaynak .

Kaset kaydedici makinesinin birincil amacı ses kaydetmek veya çalmaktır.

Bir sistem tasarlarken ses veya müzik kaydetmek veya çalmak için bir makara gerekir. Bu sistemi tasarlamak için iki olasılık vardır.

  1. makarayı makinenin içine yerleştirebiliriz
  2. yerleştirilebileceği makara için bir kanca sağlayabiliriz.

İlkini kullanırsak, makarayı değiştirmek için makineyi açmamız gerekir. ikincisini seçersek, yani makara için bir kanca yerleştirirsek, makarayı değiştirerek herhangi bir müzik çalmanın ek bir avantajını elde ederiz. ve ayrıca işlevi sadece makaradaki her şeyi oynamak için azaltır.

Bilge bağımlılık enjeksiyonu gibi, bağımsız bileşenlerin karmaşık bir sistem oluşturmak için bir araya getirilebilmesi için sadece bileşenin spesifik işlevselliğine odaklanmak için bağımlılıkları dışsallaştırma işlemidir.

Bağımlılık enjeksiyonu kullanarak elde ettiğimiz temel faydalar.

  • Yüksek kohezyon ve gevşek bağlantı.
  • Bağımlılığı dışsallaştırmak ve sadece sorumluluğa bakmak.
  • Bileşen olarak bir şeyler yapmak ve yüksek kapasiteye sahip büyük bir sistem oluşturmak için birleştirmek.
  • Bağımsız olarak geliştirildiklerinden, uygun şekilde test edildikleri için yüksek kaliteli bileşenler geliştirmeye yardımcı olur.
  • Başarısız olursa, bileşenin bir başkasıyla değiştirilmesine yardımcı olur.

Günümüzde bu kavram programlama dünyasında iyi bilinen çerçevelerin temelini oluşturmaktadır. Spring Angular vb. Bu konseptin üstüne inşa edilmiş iyi bilinen yazılım çerçeveleri

Bağımlılık enjeksiyonu, diğer nesnelerin derleme zamanında hangi işlevselliği sağlamak için kullanılacağını bilmeden veya bir nesneye özellik enjekte etme yoluna bağımlı nesnelerin örneklerini oluşturmak için kullanılan bir modeldir.

Bağımlılık enjeksiyonu örneği

Daha önce böyle bir kod yazıyoruz

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

Bağımlılık enjeksiyonu ile, bağımlılık enjektörü bizim için örneği çıkarır

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

Ayrıca okuyabilirsiniz

Kontrolün İnversiyonu ile Bağımlılık Enjeksiyonu Arasındaki Fark


17

Bağımlılık enjeksiyonu nedir?

Bağımlılık Enjeksiyonu (DI), birbirlerine bağımlı nesneleri ayırmak anlamına gelir. A nesnesinin B Nesnesine bağımlı olduğunu varsayalım, buradaki fikir bu nesneyi birbirinden ayırmaktır. Derleme süresine rağmen çalışma zamanında nesnelere bağımlılıkları paylaşmak yerine yeni anahtar sözcük kullanarak nesneyi kodlamak zorunda değiliz. Hakkında konuşursak

Bağımlılık Enjeksiyonu İlkbaharda Nasıl Çalışır:

Yeni anahtar sözcük kullanarak nesneyi kodlamak zorunda değiliz, bunun yerine yapılandırma dosyasındaki fasulye bağımlılığını tanımlayın. Yay kabı her şeyi bağlamaktan sorumlu olacaktır.

Kontrolün Ters Çevrilmesi (IOC)

IOC genel bir kavramdır ve birçok farklı şekilde ifade edilebilir ve Bağımlılık Enjeksiyonu IOC'nin somut bir örneğidir.

İki tip Bağımlılık Enjeksiyonu:

  1. Yapıcı Enjeksiyonu
  2. Setter Enjeksiyonu

1. Yapıcı tabanlı bağımlılık enjeksiyonu:

Yapıcı tabanlı DI, kapsayıcı, her biri diğer sınıfa bağımlılığı temsil eden bir dizi bağımsız değişkeni olan bir sınıf yapıcısını çağırdığında gerçekleştirilir.

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2. Setter bazlı bağımlılık enjeksiyonu:

Setter tabanlı DI, fasulyenizi somutlaştırmak için argüman oluşturucu olmayan veya argüman içermeyen statik fabrika yöntemini çağırdıktan sonra fasulyelerinizde setter yöntemlerini çağıran konteyner ile gerçekleştirilir.

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

NOT: Zorunlu bağımlılıklar için yapıcı bağımsız değişkenlerini ve isteğe bağlı bağımlılıklar için ayarlayıcıları kullanmak iyi bir kuraldır. Bir ayarlayıcıda @ Gerekli ek açıklamadan daha fazla açıklama kullanırsak, ayarlayıcıları gerekli bağımlılıklar yapmak için kullanılabileceğini unutmayın.


15

Düşünebileceğim en iyi benzetme, cerrahın ve cerrahın asistan olduğu ve ameliyat gerektiğinde çeşitli cerrahi bileşenleri sağlayan asistan olduğu bir ameliyathanedeki yardımcılarıdır. en iyi yaptığı şey (ameliyat). Asistan olmadan cerrah, her ihtiyaç duyduğunda bileşenleri kendisi almak zorundadır.

Kısaca DI, bağımlı bileşenleri getirmek için bileşenler üzerinde ortak bir ek sorumluluk (yük) ortadan kaldırmak için kullanılan bir tekniktir.

DI sizi Tek Sorumluluk (SR) prensibine yakınlaştırır surgeon who can concentrate on surgery.

DI ne zaman kullanılır: DI'yi neredeyse tüm üretim projelerinde (küçük / büyük), özellikle sürekli değişen iş ortamlarında kullanmanızı öneririm :)

Neden: Kodunuzu kolayca test edilebilir, taklit edilebilir vb. Olmasını istersiniz, böylece değişikliklerinizi hızlı bir şekilde test edebilir ve piyasaya sunabilirsiniz. Üstelik daha fazla kontrole sahip olduğunuz bir kod tabanına yolculuğunuzda sizi destekleyecek harika ücretsiz araçlar / çerçeveler varken neden olmasın.


@WindRider Teşekkürler. Daha fazla katılıyorum. İnsan hayatı ve insan vücudu tasarım mükemmelliğinin muhteşem örnekleridir ... omurga bir ESB'nin mükemmel bir örneğidir :))
Anwar Husain

15

Örnek olarak, 2 sınıf Clientve Service. ClientkullanacakService

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Bağımlılık Enjeksiyonu Olmadan

Yol 1)

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Yol 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Yol 3)

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) kullanma

Client client = new Client();
client.doSomeThingInService();

Avantajları

  • Basit

Dezavantajları

  • Test için zor Client sınıfı
  • Yapıcıyı değiştirdiğimizde Service, tüm yer oluşturma Servicenesnesindeki kodu değiştirmemiz gerekir

Bağımlılık Enjeksiyonu Kullan

Yol 1) Yapıcı enjeksiyonu

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

kullanma

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Yol 2) Setter enjeksiyonu

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

kullanma

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Yol 3) Arayüz enjeksiyonu

Kontrol Https://en.wikipedia.org/wiki/Dependency_injection adresini edin

===

Şimdi, bu kod zaten takip edilir Dependency Injectionve test Clientsınıfı için daha kolaydır .
Bununla birlikte, hala new Service()çok zaman kullanıyoruz ve değişim Serviceyapıcısında iyi değil . Bunu önlemek için DI enjektörü
1 gibi kullanabiliriz )Injector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

kullanma

Service service = Injector.provideService();

2) Kullanım kütüphanesi: Android dagger2 için

Avantajları

  • Testi kolaylaştırın
  • Değiştirdiğinizde, Serviceyalnızca Enjektör sınıfında değiştirmeniz gerekir
  • Kullanım kullanırsanız Constructor Injection, yapıcısına baktığınızda, sınıfın Clientkaç bağımlılığının olduğunu göreceksiniz.Client

Dezavantajları

  • Eğer kullanımını kullanırsanız Constructor Injection, Servicenesne oluşturulan Clientoluşturulan, bazen biz işlevi kullanmak Clientkullanmadan sınıfın Serviceböylece yaratılmış Serviceboşa

Bağımlılık Enjeksiyonu tanımı

https://en.wikipedia.org/wiki/Dependency_injection

Bağımlılık kullanılabilecek bir nesnedir ( Service)
Enjeksiyon, bağımlılığın ( Service) Clientonu kullanacak bağımlı bir nesneye ( ) geçmesidir


13

Bu, nesnelerin işlerini yapmak için gereken kadar bağımlılığa sahip olması ve bağımlılıkların az olması gerektiği anlamına gelir. Ayrıca, bir nesnenin bağımlılıkları, mümkünse “somut” nesneler üzerinde değil, arayüzlerde olmalıdır. (Somut bir nesne, new anahtar sözcüğüyle oluşturulan herhangi bir nesnedir.) Gevşek kaplin, daha fazla yeniden kullanılabilirliği, daha kolay bakımı sağlar ve pahalı hizmetler yerine kolayca "sahte" nesneler sağlamanıza olanak tanır.

“Bağımlılık Enjeksiyonu” (DI) “Kontrolün İnversiyonu” (IoC) olarak da bilinir, bu gevşek bağlantıyı teşvik etmek için bir teknik olarak kullanılabilir.

DI'nin uygulanmasında iki temel yaklaşım vardır:

  1. Yapıcı enjeksiyonu
  2. Setter enjeksiyonu

Yapıcı enjeksiyonu

Nesnelerin bağımlılığını yapıcısına geçirme tekniğidir.

Yapıcı somut bir nesneyi değil, bir arabirimi kabul ettiğini unutmayın. Ayrıca, orderdao parametresi null olduğunda bir özel durum oluştuğunu unutmayın. Bu, geçerli bir bağımlılık almanın önemini vurgulamaktadır. Yapıcı Enjeksiyonu, bence, bir nesneye bağımlılıklarını vermek için tercih edilen mekanizmadır. Nesneyi çağırırken geliştirici için açık bir şekilde yürütme için “Kişi” nesnesine hangi bağımlılıkların verilmesi gerektiği açıktır.

Setter Enjeksiyonu

Ancak aşağıdaki örneği düşünün… Diyelim ki bağımlılığı olmayan on yöntemle bir sınıfınız var, ancak IDAO'ya bağımlılığı olan yeni bir yöntem ekliyorsunuz. Yapıcıyı Enjektör Enjeksiyonunu kullanacak şekilde değiştirebilirsiniz, ancak bu sizi her yerin tüm yapıcı çağrılarında değişiklik yapmaya zorlayabilir. Alternatif olarak, bağımlılığı alan yeni bir kurucu ekleyebilirsiniz, ancak bir geliştirici bir kurucuyu diğeri üzerinde ne zaman kullanacağını nasıl kolayca bilebilir. Son olarak, bağımlılığın yaratılması çok pahalıysa, neden nadiren kullanılabileceği zaman oluşturucuya oluşturulmalı ve aktarılmalıdır? “Setter Injection” bu gibi durumlarda kullanılabilecek başka bir DI tekniğidir.

Setter Injection, bağımlılıkları yapıcıya aktarmaya zorlamaz. Bunun yerine, bağımlılıklar ihtiyacı olan nesnenin maruz kaldığı genel özelliklere ayarlanır. Daha önce ima edildiği gibi, bunu yapmak için ana motivasyonlar şunları içerir:

  1. Eski bir sınıfın yapıcısını değiştirmek zorunda kalmadan bağımlılık enjeksiyonunu desteklemek.
  2. Pahalı kaynakların veya hizmetlerin mümkün olduğunca geç ve yalnızca gerektiğinde oluşturulmasına izin vermek.

Yukarıdaki kodun nasıl görüneceğine dair bir örnek:

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;

3
Bence ilk paragrafınız sorudan uzaklaşıyor ve hiç DI'nin tanımı değil (yani, DI'yi değil SOLID'i tanımlamaya çalışıyorsunuz). Teknik olarak, 100 bağımlılığınız olsa bile, yine de bağımlılık enjeksiyonunu kullanabilirsiniz. Benzer şekilde, beton bağımlılıkları enjekte etmek de mümkündür - yine de bağımlılık enjeksiyonudur.
Jay Sullivan

10

Sanırım herkes DI için yazdığı için birkaç soru sormama izin verin ..

  1. Bir sınıfa enjekte edilecek tüm gerçek uygulamaların (arayüzlerin değil) DI konfigürasyonuna sahip olduğunuzda (örneğin, bir kontrolöre servisler için) neden bu tür bir tür kodlama değildir?
  2. Nesneyi çalışma zamanında değiştirmek istersem ne olur? Örneğin, yapılandırmam zaten MyController örneğini başlattığımda, FileLogger'ı ILogger olarak enjekte ettiğimi söylüyor. Ama DatabaseLogger'ı enjekte etmek isteyebilirim.
  3. AClass'ımın ihtiyaç duyduğu nesneleri değiştirmek istediğimde, şimdi iki yere bakmam gerekiyor - sınıfın kendisi ve yapılandırma dosyası. Bu hayatı nasıl kolaylaştırır?
  4. AClass Aproperty enjekte edilmezse, bunu taklit etmek zor mu?
  5. İlk soruya döneceğim. Yeni bir nesne () kullanmak kötüyse, arabirimi değil uygulamayı nasıl enjekte ederiz? Bence birçoğunuz aslında arayüzü enjekte ettiğimizi söylüyorsunuz, ancak konfigürasyon bu arayüzün uygulanmasını belirtmenizi sağlıyor.

Bu @Adam N tarafından verilen cevaba dayanmaktadır.

PersonService neden artık GroupMembershipService hakkında endişelenmenize gerek yok? Az önce GroupMembership'in bağlı olduğu birden fazla şey (nesne / özellik) olduğunu belirttiniz. PService'te GMService gerekiyorsa, bir mülk olarak sahip olursunuz. Enjekte edip etmediğinize bakılmaksızın bunu taklit edebilirsiniz. Enjekte edilmesini istediğim tek zaman, GMService'in çalışma zamanına kadar bilmeyeceğiniz daha spesifik alt sınıfları varsa. O zaman alt sınıfı enjekte etmek istersiniz. Veya bunu tekil veya prototip olarak kullanmak istiyorsanız. Dürüst olmak gerekirse, yapılandırma dosyası, derleme zamanı boyunca enjekte edeceği bir tip (arayüz) için hangi alt sınıfın olduğu kadar kodlanmış her şeye sahiptir.

DÜZENLE

Jose Maria Arranz tarafından DI hakkında güzel bir yorum

DI, bağımlılık yönünü belirleme ve herhangi bir tutkal kodu yazma gereksinimini ortadan kaldırarak kohezyonu arttırır.

Yanlış. Bağımlılıkların yönü XML biçimindedir veya ek açıklamalar olarak, bağımlılıklarınız XML kodu ve ek açıklamalar olarak yazılır. XML ve ek açıklamalar kaynak kodudur.

DI, tüm bileşenlerinizi modüler (yani değiştirilebilir) hale getirerek ve birbiriyle iyi tanımlanmış arayüzlere sahip olarak kuplajı azaltır.

Yanlış. Arayüzlere dayalı modüler bir kod oluşturmak için bir DI çerçevesine ihtiyacınız yoktur.

Değiştirilebilir hakkında: çok basit bir .properties arşivi ve Class.forName ile hangi sınıfların değişebileceğini tanımlayabilirsiniz. Kodunuzun HERHANGİ bir sınıfı değiştirilebiliyorsa, Java sizin için değildir, bir komut dosyası dili kullanın. Bu arada: ek açıklamalar yeniden derlenmeden değiştirilemez.

Bence DI çerçevelerinin tek bir nedeni var: kazan plakasının azaltılması. İyi yapılmış bir fabrika sistemi ile, tercih ettiğiniz DI çerçevesiyle aynı, daha kontrollü ve daha öngörülebilir yapabilirsiniz, DI çerçeveleri kod azaltma sözü verir (XML ve ek açıklamalar da kaynak kodudur). Sorun, bu kazan plakası indirgemesinin çok basit durumlarda (sınıf başına bir örnek ve benzeri) gerçek olması, bazen gerçek dünyada uygun hizmet nesnesini seçmek, bir sınıfı tek bir nesneye eşlemek kadar kolay değildir.


8

Popüler cevaplar yararsızdır, çünkü bağımlılık enjeksiyonunu yararlı olmayan bir şekilde tanımlarlar. "Bağımlılık" ile X nesnesimizin ihtiyaç duyduğu, önceden var olan başka bir nesneyi kastettiğimizi kabul edelim. Ama dediğimiz zaman "bağımlılık enjeksiyonu" yaptığımızı söylemiyoruz

$foo = Foo->new($bar);

Biz sadece yapıcıya geçen parametreleri çağırıyoruz. Bunu, inşaatçılar icat edildiğinden beri düzenli olarak yapıyoruz.

"Bağımlılık enjeksiyonu" bir tür "kontrolün ters çevrilmesi" olarak kabul edilir, bu da arayanın dışına bir miktar mantık alındığı anlamına gelir. Arayanın parametrelerden geçmesi durum böyle değildir, bu yüzden DI olsaydı, DI kontrolün ters çevrilmesi anlamına gelmez.

DI, arayan ile kurucu arasında bağımlılıkları yöneten bir ara seviye olduğu anlamına gelir. Makefile, bağımlılık enjeksiyonunun basit bir örneğidir. "Arayan", komut satırına "make bar" yazan kişidir ve "yapıcı" derleyicidir. Makefile, çubuğun fooya bağlı olduğunu belirtir ve

gcc -c foo.cpp; gcc -c bar.cpp

yapmadan önce

gcc foo.o bar.o -o bar

"Bar yapma" yazan kişinin barın fooya bağlı olduğunu bilmesine gerek yoktur. Bağımlılık "make bar" ve gcc arasında enjekte edildi.

Ara seviyenin temel amacı sadece kuruculara bağımlılıkları aktarmak değil, tüm bağımlılıkları tek bir yerde listelemek ve bunları kodlayıcıdan gizlemektir (kodlayıcının bunları sağlamasını sağlamak için değil).

Genellikle orta seviye, inşa edilen nesneler için, talep edilen her nesne tipinin yerine getirmesi gereken bir rol sağlaması gereken fabrikalar sağlar. Bunun nedeni, inşaatın detaylarını gizleyen bir ara seviyeye sahip olmanız, fabrikaların getirdiği soyutlama cezasını zaten yapmış olmanızdır, bu nedenle fabrikaları da kullanabilirsiniz.


8

Bağımlılık Enjeksiyonu bir yol anlamına gelir (aslında her şekilde) (kod diğer kısımlarını, örneğin diğer sınıfları da bağlıdır) bağımlılıkları erişmesini kodunun bir kısmı için) (örn bir sınıfı) öylesine (onları kodlanmış edilmeden modüler bir şekilde gerektiğinde özgürce değişebilir veya geçersiz kılınabilir, hatta başka bir zamanda yüklenebilir)

(ve ps, evet oldukça basit, konsept için aşırı hiper 25 $ bir isim haline geldi) , .25sentlerim


8

Zaten birçok cevap olduğunu biliyorum, ama bunu çok yararlı buldum: http://tutorials.jenkov.com/dependency-injection/index.html

Bağımlılık Yok:

public class MyDao {

  protected DataSource dataSource = new DataSourceImpl(
    "driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}     
}

Bağımlılık:

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String password) {
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey) {...}
}

Örneklemenin bir kurucuya nasıl DataSourceImpltaşındığına dikkat edin . Yapıcı, tarafından istenen dört değer olan dört parametre alır DataSourceImpl. MyDaoSınıf hala bu dört değere bağlı olsa da , artık bu bağımlılıkları karşılamıyor. MyDaoÖrnek oluşturan her sınıf tarafından sağlanır .


1
DI, DataSourceImp'ınızın önceden oluşturulmuş arabiriminden geçmez mi?
PmanAce

6

Bağımlılık enjeksiyonu, genel olarak "Bağımlılık Gizleme" şartı olarak adlandırılabilecek olası bir çözümdür. Bağımlılık Gizleme, 'açık' doğayı, onu gerektiren bir sınıfa bağımlılık sağlama ve dolayısıyla bir şekilde söz konusu sınıfa bağımlılığın sağlanmasını bir şekilde gizleme sürecinden çıkarma yöntemidir. Bu mutlaka kötü bir şey değil. Aslında, bir sınıfa bağımlılık sağlama şeklini gizleyerek, o zaman sınıfın dışındaki bir şey bağımlılığı yaratmaktan sorumludur; bu, çeşitli senaryolarda, sınıfa herhangi bir değişiklik yapmadan farklı bir bağımlılık uygulamasının sağlanabileceği anlamına gelir. sınıfa. Bu, üretim ve test modları arasında geçiş yapmak için mükemmeldir (örneğin, 'sahte' hizmet bağımlılığı kullanarak).

Ne yazık ki kötü yanı, bazı insanların bağımlılık gizleme yapmak için özel bir çerçeveye ihtiyacınız olduğunu varsayması ve bunu yapmak için belirli bir çerçeve kullanmamayı seçerseniz bir şekilde 'daha az' bir programcı olmanızdır. Birçoğu tarafından inanılan son derece rahatsız edici bir efsane, bağımlılık enjeksiyonunun bağımlılık şaşkınlığına ulaşmanın tek yolu olmasıdır. Bu açıkça ve tarihsel olarak ve açıkça% 100 yanlıştır, ancak bazı insanları bağımlılık gizleme gereksinimleriniz için bağımlılık enjeksiyonuna alternatifler olduğuna ikna etmekte zorluk çekeceksiniz.

Programcılar yıllardır bağımlılık gizleme gereksinimini anladılar ve bağımlılık enjeksiyonunun tasarlanmasından önce ve sonra birçok alternatif çözüm geliştirildi. Fabrika desenleri vardır, ancak belirli bir örneğe enjeksiyon yapılmaması gereken ThreadLocal kullanarak birçok seçenek vardır - nesneyi kullanılabilir hale getirme avantajına sahip olan konuya bağımlılık etkili bir şekilde enjekte edilir (statik statik alıcı yöntemleri ile) herhangi bir kişiyegerektiren sınıflara ek açıklama eklemek zorunda kalmadan bunu gerektiren sınıf ve bunu gerçekleştirmek için karmaşık XML 'tutkal' oluşturun. Kalıcılık için bağımlılıklarınız gerektiğinde (JPA / JDO ya da her neyse), 'şeffaflık kalıcılığı' çok daha kolay ve sadece POJO'lardan oluşan etki alanı modeli ve iş modeli sınıflarıyla (yani ek açıklamalarda çerçeveye özgü / kilitli olmayan) ulaşmanızı sağlar.



5

Teknik açıklamaya gitmeden önce bunu gerçek hayattan bir örnekle görselleştirin, çünkü bağımlılık enjeksiyonunu öğrenmek için çok fazla teknik şey bulacaksınız, ancak benim gibi insanların temel kavramını alamadığı maksimum zaman.

İlk resimde, çok sayıda birleşime sahip bir otomobil fabrikanız olduğunu varsayalım . Montaj ünitesine aslında bir araba yerleştirilmiş ancak motor , koltuk ve tekerleklere ihtiyacı var . Yani montaj birimi bu tüm birimlere bağımlıdır ve bağımlılıklar fabrikanın .

Artık bu fabrikadaki tüm görevleri sürdürmek için çok karmaşık olduğunu hissedebilirsiniz, çünkü ana görevle birlikte (Montaj ünitesinde araba montajı) da odaklanmanız gerekir diğer ünitelere . Artık bakımı çok pahalı ve fabrika binası çok büyük, bu yüzden kiralık ekstra dolar alır.

Şimdi ikinci resme bakın. Size kendi üretim maliyetinizden daha ucuz tekerlek , koltuk ve motor sağlayacak bazı sağlayıcı şirketler bulursanız , şimdi bunları fabrikanızda yapmanız gerekmez. Şimdi sadece montaj biriminiz için daha küçük bir bina kiralayabilirsiniz için bakım görevinizi azaltacak ve ekstra kiralama maliyetinizi azaltacak kiralayabilirsiniz. Artık sadece ana görevinize de odaklanabilirsiniz (Araba montajı).

Şimdi bir araba monte etmek için tüm bağımlılıkların fabrikadan sağlayıcılardan enjekte edildiğini söyleyebiliriz . Gerçek hayattaki Bağımlılık Enjeksiyonu (DI) örneğidir .

Şimdi teknik kelimede, bağımlılık enjeksiyonu bir nesnenin (veya statik yöntemin) başka bir nesnenin bağımlılıklarını sağladığı bir tekniktir. Bu nedenle, nesneyi yaratma görevini başka birine aktarma ve doğrudan bağımlılığı kullanma, bağımlılık enjeksiyonu olarak adlandırılır.

Bu , şimdi DI'yi bazı teknik kelimelerle öğrenmenize yardımcı olacaktır. Bu DI ne zaman kullanılacağını gösterecek ve ne zaman gerektiği değil .

Hepsi bir araba fabrikasında.

Basit araba fabrikası


1
40 ish arasında en açık cevap. Gerçek hayattan örnek ve görüntüler. +1. Kabul edilen cevap olmalı.
Marche Remi

4

Kitap Apress.Spring.Persistence.with.Hibernate.Oct.2010

Bağımlılık enjeksiyonunun amacı, harici yazılım bileşenlerini uygulama iş mantığınızdan çözme işini birbirinden ayırmaktır. Bu sadece hata olasılığını arttırmakla kalmaz, kod şişmesi ekler ve bakım karmaşıklığını artırır; bileşenleri yeniden birleştirir, böylece yeniden düzenleme veya test sırasında bağımlılıkları değiştirmeyi zorlaştırır.


4

Bağımlılık Enjeksiyonu (DI), OOP'nin temel özelliğini kullanan bir tasarım paterninden biridir - bir nesnede başka bir nesneyle ilişki. Kalıtım, bir nesneyi daha karmaşık ve spesifik bir başka nesne yapmak için miras alırken, ilişki veya ilişkilendirme, öznitelik kullanarak bir nesneden başka bir nesneye bir işaretçi oluşturur. DI'nin gücü, arayüzler ve gizleme kodu gibi OOP'un diğer özellikleriyle kombinasyon halindedir. Kütüphanede basitlik için yalnızca bir kitap ödünç alabilen bir müşterimiz (abone) olduğunu varsayalım.

Kitabın arayüzü:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

Sonra birçok kitap türümüz olabilir; türlerden biri kurgu:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

Artık abonenin kitapla ilişkisi olabilir:

package com.deepam.hidden;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

Her üç sınıf da kendi uygulaması için gizlenebilir. Şimdi bu kodu DI için kullanabiliriz:

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

Bağımlılık enjeksiyonunu kullanmanın birçok farklı yolu vardır. Singleton, vb. İle birleştirmek mümkündür, ancak yine de temelde, sadece başka bir nesnenin içinde nesne türünün niteliği yaratılarak gerçekleştirilir. Yararlılığı sadece ve sadece özellik olarak, tekrar tekrar yazmamız gereken bu kod her zaman bizim için hazırlanır ve yapılır. Bu nedenle DI, Inversion of Control (IoC) ile bu kadar yakından bağlanmıştır, bu da programımızın kodumuza fasulye enjeksiyonu yapan başka bir çalışan modülü kontrol ettiği anlamına gelir. (Enjekte edilebilecek her nesne imzalanabilir veya Fasulye olarak kabul edilebilir.) Örneğin, İlkbaharda, oluşturma ve başlatma ile yapılır. ApplicationContextbizim için işe yarayan bir kap. Biz sadece kodumuzda Bağlam yaratırız ve fasulye başlatmayı çağırırız. O anda enjeksiyon otomatik olarak yapıldı.


4

5 yaşındakiler için Bağımlılık Enjeksiyonu.

Gidip kendiniz buzdolabından bir şeyler çıkardığınızda sorunlara neden olabilirsiniz. Kapıyı açık bırakabilirsin, anne ya da baba senin istemediğin bir şey alabilirsin. Hatta sahip olmadığımız veya süresi dolmuş bir şeyi bile arıyor olabilirsiniz.

Yapmanız gereken şey, "öğle yemeği ile bir şeyler içmem gerekiyor" demek ve sonra yemek için oturduğunuzda bir şeyler olduğundan emin olacağız.


1
Bu açıkça bir ebeveynin cevabıdır. ;)
Marche Remi

4

Pablo Deeleman'ın “Learning Angular - Second Edition” adlı kitabı Christoffer Noring'den:

" Uygulamalarımız büyüdükçe ve geliştikçe, kod varlıklarımızın her biri dahili olarak yazılım mühendisliği dünyasında bağımlılıklar olarak bilinen diğer nesnelerin örneklerini gerektirecektir . Bu tür bağımlılıkları bağımlı istemciye geçirme eylemi enjeksiyon olarak bilinir , ve aynı zamanda adında başka bir kod varlık, katılımını gerektirir enjektör . enjektör sorumluluğunu alacak başlatmasını ve ön yükleme gereken bağımlılıklarıböylece müşteriye başarıyla enjekte edildikleri andan itibaren kullanıma hazırdırlar. Bu çok önemlidir çünkü müşteri kendi bağımlılıklarını nasıl somutlaştıracağına dair hiçbir şey bilmiyor ve sadece arayüzün farkında onları kullanmak için uyguladıkları . "

Gönderen: Anton Moiseev. “Dizgi ile Açısal Gelişim, İkinci Baskı” kitabı:

“Kısacası, DI kodu gevşek bir şekilde yazmanıza yardımcı olur ve kodunuzu daha test edilebilir ve tekrar kullanılabilir hale getirir .”


3

Basit bir ifadeyle, bağımlılık enjeksiyonu (DI), farklı nesne arasındaki bağımlılıkları veya sıkı bağlantıyı ortadan kaldırmanın yoludur. Bağımlılık Enjeksiyonu her nesneye uyumlu bir davranış kazandırır.

DI, “Bizi arama, biz sizi arayacağız” diyen IOC Spring müdürünün uygulamasıdır. Bağımlılık enjeksiyon programcısı kullanmanın yeni anahtar kelimeyi kullanarak nesne oluşturması gerekmez.

Nesneler bir kez Spring kapsayıcısına yüklenir ve daha sonra getBean (String beanName) yöntemini kullanarak Spring kapsayıcısından bu nesneleri alarak onları gerektiğinde yeniden kullanırız.


3

Bağımlılık enjeksiyonu, Spring Framework ile ilgili kavramın kalbidir.Herhangi bir proje baharının çerçevesini oluştururken hayati bir rol oynayabilir ve burada bağımlılık enjeksiyonu sürahi içinde gelir.

Aslında, Java'da A sınıfı ve B sınıfı olarak iki farklı sınıf oluşturduğunuzu ve A sınıfında kullanmak istediğiniz B sınıfında her ne tür bir işlev oluşturduğunuzu varsayalım, o zaman bağımlılık enjeksiyonu kullanılabilir. burada bir sınıftaki nesneyi diğer sınıfta sandığınız gibi, aynı şekilde başka bir sınıftaki tüm sınıfın erişilebilir olmasını sağlamak için enjekte edebilirsiniz. bu şekilde bağımlılığın üstesinden gelinebilir.

BAĞIMSIZLIK ENJEKSİYONU İKİ SINIF SÜRDÜRÜLEBİLİR VE AYNI ZAMANDA AYRI AYIRTIR.

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.