Soru Bağımlılık enjeksiyonu nedir?


Belirli sorularla ilgili çoktan sorulan sorular var. bağımlılık enjeksiyonuBunu ne zaman kullanacağınız ve bunun için hangi çerçeveler olduğu gibi. Ancak,

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


2635
2017-09-25 00:28


Menşei


Dependency Enjeksiyon konusundaki tartışmamı görün İşte. - Kevin S.
Bağlantılarla ilgili yorumlara katılıyorum. Başka birine referans vermek isteyebileceğini anlayabiliyorum. Ama en azından neden onları bağladığınızı ve bu bağlantıyı google'ı kullanarak alabildiğim diğer bağlantılardan daha iyi kılan şeyleri ekleyin. - Christian Payne
@AR: Teknik olarak Bağımlılık Enjeksiyonu değil özel bir IoC formu. Daha ziyade, IoC Bağımlılık Enjeksiyonu sağlamak için kullanılan bir tekniktir. Bağımlılık Enjeksiyonunu sağlamak için başka teknikler de kullanılabilir (her ne kadar ortak kullanımda IoC olsa da) ve IoC diğer birçok problem için de kullanılır. - Sean Reilly
Eğer özetlemezseniz, onun gitmesi ve okumak için harcadığı çabayı bilmiyoruz. - Casebash
Bağlantılarla ilgili olarak, genellikle bir şekilde veya başka bir şekilde yok olduklarını unutmayın. SO cevaplarında giderek artan sayıda ölü bağlantı var. Yani, bağlantılı makalenin ne kadar iyi olursa olsun, bulamıyorsan hiç iyi değil. - DOK


Cevaplar:


Temel olarak, nesnelerinizin bir bağımlılık yaratması ya da bir fabrika nesnesinin kendileri için bir şey yapmasını istemek yerine, gerekli bağımlılıkları dışarıdaki nesneye aktarırsınız ve onu başka birinin sorunu haline getirirsiniz. Bu "birisi", bağımlılık grafiğini ya da bağımlılık grafiğini oluşturan bağımlılık enjektörü (çerçeve) kadar bir nesnedir. Burada kullandığım bir bağımlılık, geçerli nesnenin bir referansa sahip olması gereken başka bir nesnedir.

Bağımlılık enjeksiyonunun en büyük avantajlarından biri testlerin daha kolay yapılabilmesidir. Yapıcısında böyle bir şey yapan bir nesneye sahip olduğunuzu varsayalım:

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

Tüm yapmak istediğinizde, özellikle de bazı diskler MyObject karmaşık disk veya ağ erişimi yapan bir şey ise, SomeClass bazı birim testleri çalıştırdığınızda sorun çıkartabilir. Yani şimdi myObject'e alay ediyorsun ama aynı zamanda bir şekilde fabrika aramasını da kesiyorsun. Zor. Bunun yerine, nesneyi yapıcıya bir argüman olarak iletin. Artık sorunu başka bir yere taşıdınız, ancak testler çok daha kolay olabilir. Sadece bir kukla myObject yapın ve bunu içeri aktarın. Kurucu şimdi biraz şöyle görünecekti:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Bu, bağımlılık enjeksiyonunun bir tarzıdır - kurucu aracılığıyla. Çeşitli mekanizmalar mümkündür.

  • Yorumlarda belirtildiği gibi, ortak bir alternatif, hiçbir şey yapıcı bir kurucu tanımlamaktır ve bağımlılıkların mülk belirleyicileri (h / t @ MikeVella) tarafından enjekte edilmesidir.
  • Martin Fowler Üçüncü bir alternatifi (h / t @MarcDix) belgelendirir, burada sınıflar enjekte etmek istedikleri bağımlılıklar için bir arabirimi açıkça uygular.

Bağımlılık enjeksiyonu kullanılmadığı zaman (örneğin kurucularında çok fazla çalışma yapan sınıflarda olduğu gibi), birim testindeki bileşenleri ayırmak çok daha zor olur.

2013'te bu cevabı yazdığımda, bu büyük bir temaydı. Google Test Blogu. Bu, çalışma zamanı tasarımınızda her zaman ekstra esnekliğe ihtiyaç duymayacağınız için (örneğin servis belirleyici veya benzer modeller için) her zaman benim için en büyük avantaj olmaya devam etmektedir, ancak testler sırasında sınıflarınızı ayırmanız gerekir.


1638
2017-09-25 00:49



Ben Hoffstein'ın Martin Fowler'ın makalesine atıfta bulunarak bu konudaki bir 'okumayı okumayı' işaret etmenin gerekli olduğunu kabul ettiğimde, bu sorunun cevabını SO yanıtına verdiği için Wds 'cevabını kabul ediyorum. - AR.
Açıklama ve motivasyon için +1: Bir sınıfın bir başkasının problemine bağlı olduğu nesnelerin yaratılmasını sağlamak. Bunu söylemenin başka bir yolu da, DI sınıflarını daha tutarlı hale getirmesidir (daha az sorumlulukları vardır). - Fuhrmanator
Bağımlılığın "yapıcıya" geçtiğini söylüyorsun ama anladığım kadarıyla bu kesinlikle doğru değil. Nesnenin örneklendirilmesinden sonra bağımlılık bir özellik olarak ayarlanmışsa hala bağımlılık enjeksiyonu doğru mu? - Mike Vella
@MikeVella Evet, bu doğru. Çoğu durumda gerçek bir fark yaratmaz, ancak özellikler genellikle biraz daha esnektir. Metni biraz belirterek bunu belirteceğim. - wds
Şimdiye kadar bulduğum en iyi cevaplardan biri, bu yüzden onu geliştirmekle gerçekten ilgileniyorum. Üçüncü form bağımlılık enjeksiyonunun bir açıklaması eksik: Arayüz enjeksiyon. - Marc Dix


Şimdiye kadar bulduğum en iyi tanım James Shore'dan biri:

"Bağımlılık Enjeksiyonu" 25 dolar   5-cent kavramı için terim. [...]   Bağımlılık enjeksiyonu,   Örnek değişkenlerini nesneler. [...].

Var Martin Fowler'ın bir makalesi Bu da yararlı olabilir.

Bağımlılık enjeksiyonu temel olarak bir nesnenin kendisini inşa etmesini gerektirmek yerine ihtiyaç duyduğu nesneleri (bağımlılıkları) sağlar. Bağımlılıkların alay edilmesine veya dışarı çıkmasına izin verdiğinden, test için çok kullanışlı bir tekniktir.

Bağımlılıklar, birçok yolla (kurucu enjeksiyonu veya ayarlayıcı enjeksiyonu gibi) nesneler içine enjekte edilebilir. Bunu yapmak için özel bağımlılık enjeksiyon çerçeveleri (ör. Bahar) bile kullanılabilir, ancak kesinlikle gerekli değildir. Bağımlılık enjeksiyonu için bu çerçevelere ihtiyacınız yok. Nesneleri (bağımlılıkları) taklit etmek ve iletmek açıkça, çerçeve tarafından enjeksiyon olarak iyi bir enjeksiyondur.


2063
2017-09-26 16:50



James'in makalesinin, özellikle de sonunun açıklamasını beğeniyorum: "Yine de, üç kavramı ('TripPlanner,' 'CabAgency' ve 'AirlineAgency') alan herhangi bir yaklaşıma hayret etmelisiniz. ve daha sonra tek bir uygulama mantığı yazılmadan önce düzinelerce tutkal kodu ve yapılandırma XML satırı ekler. " Bu çok sık (ne yazık ki) gördük nedir - (onun tarafından açıklandığı gibi, kendi başına iyidir) o bağımlılık enjeksiyon kolay yapılabilirdi şeyler overcomplicate için kötüye kullanılmaktadır - "destekleme" yazma biten kod ... - Matt
Re: "Nesnelerin (bağımlılıkların) örneklenmesi ve geçişi açıkça, çerçeve ile enjeksiyon olarak iyi bir enjeksiyondur." Öyleyse insanlar neden bunu yaptı? - dzieciou
Her çerçevenin aynı nedenden ötürü (ya da en azından şöyle yazılmalıdır) yazdığı gibi: çünkü belirli bir karmaşıklığa ulaştığınızda yazılması gereken bir çok tekrarlı / kodlu kod vardır. Sorun, çoğu zaman ihtiyaç duyulmadığı zamanlarda bile, bir çerçeve için birçok kez ulaşacak olan sorun. - Thiago Arrais
Bu doğru cevap olmalı ... "Bağımlılık enjeksiyonu 'bir nesne referansını geçiyor" - Hal50000
5 cent'lik bir kavram için 25 dolarlık süre öldü. İşte bana yardımcı olan iyi bir yazı: codeproject.com/Articles/615139/... - Hill


Bu komik örneği anlam bakımından buldum. gevşek kaplin:

Herhangi bir uygulama, bazı yararlı şeyler yapmak için birbiriyle işbirliği yapan birçok nesneden oluşur. Geleneksel olarak her nesne, birlikte çalıştığı bağımlı nesnelere (bağımlılıklar) kendi referanslarını elde etmekten sorumludur. Bu, yüksek bağlanmış sınıflara ve test edilmesi zor kodlara yol açar.

Örneğin, bir düşünün Car nesne.

bir Car Çalıştırmak için tekerlekler, motor, yakıt, akü vb. Geleneksel olarak, bu tür bağımlı nesnelerin markasını, Car nesne.

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

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

  //The rest
}

İşte Car nesne bağımlı nesneleri oluşturmaktan sorumludur.

Ya bağımlı nesnesinin türünü değiştirmek istiyorsak Wheel - başlangıçtan sonra NepaliRubberWheel() delikler? Araba nesnesini yeni bağımlılığıyla yeniden yaratmalıyız. ChineseRubberWheel()ama sadece Car üretici bunu yapabilir.

O zaman ne yapar Dependency Injection Bizi için ...

Bağımlılık enjeksiyonunu kullanırken, nesnelere bağımlılıkları verilir. çalışma zamanı yerine derleme zamanı (otomobil üretim zamanı). Böylece şimdi değiştirebiliriz Wheel ne zaman istersen. İşte dependency (wheel) içine enjekte edilebilir Car işlem esnasında.

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

Buradayız enjekte  bağımlılıklar Çalışma 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


507
2018-05-22 04:01



Bunu anlama biçimim, yeni bir nesneyi başka bir nesnenin parçası olarak ortaya koymak yerine, söz konusu nesneyi gerektiğinde ve gerektiğinde ilk nesnenin bağımlılığını kaldırarak enjekte edebiliriz. Bu doğru mu? - JeliBeanMachine
Bunu bir kahve dükkanı örneğiyle burada anlattım:digigene.com/design-patterns/dependency-injection-coffeeshop - Ali Nem
Gerçekten bu benzetmeyi seviyorum çünkü basit bir benzetmeyle düz İngilizce. saygın lastik üreticilerini mevcut olup olmadığını, neden bunu yapmak, yani bir lastik üretimi bölünme yapmak için sıfırdan başlamalı Ben zaten monte hattı yuvarlan tasarımdan bir araba yapmaya çok fazla maddi geçirdi ve insan gücü, Toyota olduğumu söyle new bir lastik? Yapmıyorum. Tek yapmam gereken, onlardan (param ile enjekte et) satın al, yükle ve wah-lah! Programlamaya geri dönerek, bir C # projesinin var olan bir kütüphaneyi / sınıfı kullanması gerektiğini söyleyin, bunun için iki yol vardır: - Jeb50
(con't), .. harici kütüphane / sınıf veya 2-DLL'den ekleyin. Bu harici sınıfın içinde ne olduğunu görmemiz gerekmedikçe, DLL olarak eklemek daha kolay bir yoldur. Yani seçenek 1 new Bu seçenek 2 param olarak geçer. Doğru olmayabilir, ama anlaşılması kolay basit aptal. - Jeb50
Muhteşem açıklama, - Avan


Bağımlılık Enjeksiyon, nesnelerin, içsel olarak inşa etmek yerine, diğer kod parçalarından nesnelerin örneklerini aldıkları bir şekilde tasarlandığı bir uygulamadır. Bu, nesnenin gerektirdiği arabirimi uygulayan herhangi bir nesnenin kodu değiştirmeden değiştirilebileceği anlamına gelir, bu da testi basitleştirir ve dekuplajı geliştirir.

Örneğin, şu ipuçlarını 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, uygulama PersonService::addManager ve PersonService::removeManager İşini yapmak için GroupMembershipService'in bir örneğine ihtiyaç duyardı. Bağımlılık Enjeksiyonu olmaksızın, bunu yapmanın geleneksel yolu yeni bir şey yaratmaktır. GroupMembershipService kurucu PersonService ve bu özniteliği her iki işlevde de kullanın. Ancak, kurucunun GroupMembershipService gerektirdiği birçok şey var veya daha da kötüsü, çağrılacak bazı başlatma "ayarlayıcıları" var GroupMembershipService, kod oldukça hızlı büyür ve PersonServiceşimdi sadece GroupMembershipService ama aynı zamanda her şey GroupMembershipService bağlıdır. Ayrıca, bağlantı GroupMembershipService içine kodlanmış PersonService Bu, "kukla" olamayacağınız anlamına gelir GroupMembershipService Test amaçlı veya uygulamanızın farklı bölümlerinde bir strateji modeli kullanmak için.

Bağımlılık Enjeksiyonu ile, GroupMembershipService senin içinde PersonServiceya da PersonService kurucu, ya da yerel bir örneğini ayarlamak için bir Özellik (alıcı ve ayarlayıcı) ekleyin. Bu demektir ki PersonService artık nasıl oluşturulacağı konusunda endişelenmenize gerek yok GroupMembershipServiceSadece verilenleri kabul eder ve onlarla çalışır. Bu aynı zamanda bir alt sınıf olan bir şey anlamına gelir GroupMembershipServiceya da uygular GroupMembershipService arayüz içine "enjekte edilebilir" PersonService, ve PersonService değişiklik hakkında bilmemize gerek yok.


233
2017-09-25 06:49



DI kullanarak AFTER kullanarak aynı kod örneğini verebilirseniz harika olurdu - CodyBugstein
Keşke python'un böyle birşeyi olsaydı. Şu anda test etmek için her şeyle dalga geçmek zorundayız. - user2601010
Kesinlikle yapabilirsin yap Python ile bağımlılık enjeksiyonu, ama büyük kütüphanelerin (Django, vb) çoğu python alaycı kütüphaneleri çok sağlam olduğu için değildir. DI kullandığınızda hala mock yazmak zorundasınız, sadece daha kolay. - Adam Ness


Kabul edilen cevap iyi bir şeydir - ancak buna ek olarak DI'nin koddaki sabit kodlanmış sabitlerin klasik kaçışından çok daha çok hoşlandığını eklemek isterim.

Bir veritabanı adı gibi bir sabit kullandığınızda, kodu kodun içinden bir miktar yapılandırma dosyasına hızlıca taşırsınız ve bu değeri içeren bir değişkeni ihtiyaç duyulan yere iletirsiniz. Bunun 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 yönelimli programlama dünyasında buna benzemektedir. Sabit değişmezler yerine oradaki değerler tüm nesnelerdir - ancak onları koddan çıkartan kodun sınıf kodundan çıkarılmasının nedeni benzerdir - nesneler daha sonra bunları kullanan kodla daha sık değişir. Böyle bir değişikliğin gerekli olduğu önemli bir durum testlerdir.


142
2018-01-06 18:33



+1 "nesneler, daha sonra bunları kullanan kodu daha sık değiştirir". Genelleştirmek için, akı noktalarında bir indirekt ekleyin. Akı noktasına bağlı olarak, indirimler farklı isimlerle çağrılır! - Chethan
"koddaki kodlanmış sabitlerin klasik olarak kaçınıyor" - dsdsdsdsd


Balık tutmaya gitmek istediğinizi hayal edelim:

  • Bağımlılık enjeksiyonu olmadan, herşeyin kendinizle ilgilenmeniz gerekir. Bir tekne bulmanız, bir olta satın almanız, yem aramanız vb. Şeyler bulmanız gerekiyor. Elbette ki bu mümkün ama size çok fazla sorumluluk yüklüyor. Yazılım terimlerinde, tüm bu şeyler için bir arama yapmanız gerektiği anlamına gelir.

  • Bağımlılık enjeksiyonu ile başka biri, tüm hazırlığı yapar ve gerekli ekipmanı size sunar. Tekneyi, olta ve yemleri - (“enjekte edilmek”) alacaksınız - hepsi kullanıma hazır.


96
2017-10-22 04:47



Flipside, banyonuzu yeniden yapmak için bir tesisatçı tuttuğunu hayal et, sonra "Benim için almam gereken araçların ve malzemenin bir listesi" diyor. Bu tesisatçı işi değil mi? - Josh Caswell
Bu yüzden birisinin hiç kimsenin bilmediği bir kimsenin ilgilenmesine ihtiyacı vardır. Fakat yine de kullanmaya hazır olsa da, tekne, sopa ve yem listesini almaya karar verir. - Chookoos
@JoshCaswell Hayır, bu tesisatçının emitörünün işi. Bir müşteri olarak tesisat yapmak gerekir. Bunun için bir tesisatçıya ihtiyacınız var. Tesisatçının araçları lazım. Bunları almak için tesisat şirketi tarafından donatılıyor. Bir müşteri olarak tesisatçının ne yaptığını veya neye ihtiyacı olduğunu tam olarak bilmek istemezsiniz. Bir tesisatçı olarak neye ihtiyacın olduğunu biliyorsun, ama sen sadece işini yapmak istiyorsun, her şeyi alamıyorsun. Tesisatçılar işvereni olarak tesisatçılarınızı, insanların evlerine göndermeden önce ihtiyaç duydukları şeyle donatmakla yükümlü olursunuz. - kai
@kai Ben senin noktanı anlıyorum. Yazılımda bir fabrikadan bahsediyoruz, doğru mu? Ancak DI aynı zamanda genellikle sınıfın hala enjekte edilmediği bir fabrika kullanmadığı anlamına gelir. Siz, müşteri, size araçları vermek için işverenle (fabrika) irtibat kurmanız gerekir, böylece tesisatçıya geçebilirsiniz. Aslında bu bir programda nasıl çalışır? Böylece müşteri (çağrı sınıfı / işlev / her ne olursa olsun) araçları temin etmek zorunda olmasa da, işverenden (fabrika) tesisatçıya (enjekte edilen sınıf) bunu sağladıklarından emin olmak için hala orta adam olmak zorundadırlar. - KingOfAllTrades
@KingOfAllTrades: Elbette bir noktada tesisatçıları işe almak ve donatmak için birine sahip olmak zorundasınız, yoksa tesisatçılarınız yok. Ama müşterinin bunu yapmasına sahip değilsin. Müşteri sadece bir tesisatçı ister ve işini yapmak için ihtiyaç duyduğu şeyle donatılır. DI ile, hala bağımlılıkları yerine getirmek için bazı kod var. Ama onu gerçek iş yapan koddan ayırıyorsunuz. Eğer onu en geniş ölçüde alırsanız, nesnelerin bağımlılıkları bilinir ve nesne-grafik oluşturma çoğu zaman init kodunda olur. - cHao


Bu en basit açıklamadır Bağımlılık Enjeksiyonu ve Bağımlılık Enjeksiyon Konteyneri Gördüğüm:

Bağımlılık Enjeksiyonu Olmadan

  • Uygulama Foo'ya (ör. Bir kontrolör) ihtiyaç duyar, yani:
  • Uygulama Foo oluşturur
  • Uygulama Foo çağırır
    • Foo'nun Bar'a (ör. Bir servis) ihtiyacı vardır, yani:
    • Foo Bar oluşturur
    • Foo Bar çağırır
      • Bar Bim'e ihtiyaç duyar (bir servis, bir depo, …), yani:
      • Bar Bim oluşturur
      • Barda bir şey var

Bağımlılık Enjeksiyonu ile

  • Uygulama, Bim'e ihtiyaç duyan Bar'a ihtiyaç duyan Foo'ya ihtiyaç duyuyor:
  • Uygulama Bim oluşturur
  • Uygulama Bar oluşturur ve verir Bim
  • Uygulama Foo oluşturur ve Bar verir
  • Uygulama Foo çağırır
    • Foo Bar çağırır
      • Barda bir şey var

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

  • Uygulama Foo'ya ihtiyaç duyar:
  • Uygulama, Konteyner'den Foo alır, bu nedenle:
    • Konteyner Bim oluşturur
    • Konteyner Bar oluşturur ve verir Bim
    • Konteyner Foo yaratır ve Bar verir
  • Uygulama Foo çağırır
    • Foo Bar çağırır
      • Barda bir şey var

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

  • Bağımlılık En iyi kod yazmak için bir yöntemdir
  • DI Konteyner, bağımlılıkları enjekte etmeye yardımcı olan bir araçtır

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


79
2018-05-05 11:53



@Trix Bağımlılık enjeksiyon kullanmak ya da değil mi? - roottraveller
@rootTraveller google arkadaşın: Bağımlılık enjeksiyon modelini ne zaman kullanmak uygun değildir? - Trix


Basit örneklerle deneyelim araba ve Motor sınıflar, herhangi bir araba en azından şimdilik, herhangi bir yere gitmek için bir motora ihtiyaç duyar. Kodun bağımlılık enjeksiyonu olmadan nasıl görüneceği 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ı örneklendirmek için bir sonraki kodu kullanacağız:

Car car = new Car();

GasEngine'e sıkı sıkıya bağlı olduğumuz ve bu kodu ElectricityEngine olarak değiştirmeye karar verirsek, bu kodla ilgili sorun o zaman Car sınıfını yeniden yazmamız gerekecek. Ve uygulama ne kadar büyükse, daha fazla sorun ve baş ağrısına yeni motor tipi eklemek ve kullanmak zorundayız.

Başka bir deyişle, bu yaklaşımla yüksek seviyeli Car sınıfımızın, SOLID'den Bağımlılık İnversiyon Prensibini (DIP) ihlal eden daha düşük seviyedeki GasEngine sınıfına bağlı olması. DIP, somut sınıflara değil soyutlamaya bağlı olmamızı önerir. Bu nedenle, IEngine arayüzünü tanıtıyoruz ve aşağıdaki gibi kodu yeniden yazıyoruz:

    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();
        }
    }

Artık bizim Car sınıfımız sadece IEngine arayüzüne bağlı, motorun özel bir uygulaması değil. Şimdi tek ipucu, bir Araba örneğini nasıl oluşturabiliriz ve ona GasEngine veya ElectricityEngine gibi gerçek bir beton Motoru sınıfı verir. Bu nerede Bağımlılık Enjeksiyonu içeri gelir.

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

Burada temel olarak bizim bağımlılığımızı (Motor örneği) Araba yapıcısına enjekte ediyoruz. Yani şimdi sınıflarımız nesneler ve onların bağımlılıkları arasında gevşek bir bağ var ve biz de Car sınıfını değiştirmeden yeni tip motorları kolayca ekleyebiliriz.

Ana faydası Bağımlılık Enjeksiyonu Bu sınıflar daha gevşek bağlanmışlardır çünkü sabit kodlanmış bağımlılıkları yoktur. Bu, yukarıda belirtilen Bağımlılık İnversiyon Prensibini izler. Belirli uygulamalara başvurmak yerine, sınıflar soyutlamalar ister (genellikle arayüzleri) sınıf inşa edildiğinde onlara sağlanan.

Yani sonunda Bağımlı enjeksiyon sadece bir tekniktir   nesneler ve onların bağımlılıkları arasında gevşek birleştirme sağlamak.   Sınıfın ihtiyacı olan bağımlılıkları doğrudan ortaya koymaktan ziyade   eylemlerini gerçekleştirme emri, bağımlılıklar sınıfa verilir   (çoğunlukla) kurucu enjeksiyonu ile.

Ayrıca birçok bağımlılığa sahip olduğumuzda, Inversion of Control (IoC) kapsayıcılarını kullanmak için çok iyi bir yöntemdir. Hangi arabirimlerin tüm bağımlılıklarımız için hangi somut uygulamalarla eşleştirilmesi gerektiğini ve bu bağımlılıkları bizim için inşa ettiğimizde çözebiliriz. bizim neslimiz. Örneğin, IoC konteynerinin eşleştirmesinde IEngine bağımlılık haritasına eşlenmelidir Gaz motoru sınıfımızın bir örneği için IoC konteynırını sorduğumuzda araba sınıf, otomatik olarak bizim inşa edecek araba bir sınıf Gaz motoru bağımlılık geçti.

GÜNCELLEŞTİRME: Yakın zamanda Julie Lerman'dan EF Core'u izledim ve DI hakkında kısa bir tanımını beğendim.

Bağımlılık enjeksiyonu, uygulamanızın enjekte edilmesine izin veren bir desendir.   onları zorlamadan, onlara ihtiyaç duyan sınıflara uçmak   Bu nesnelerden sorumlu olacak sınıflar. Kodunuzun olmasını sağlar   Daha gevşek bir şekilde bağlanmış ve Entity Framework Core da buna benzer   hizmet sistemi.


77
2017-07-06 09:42



Güzel açıklama, neden bu kadar oy yok? - nhoxbypass
Bu en iyi cevaplardan biri olmayı hak ediyor. - Shwetabh Shekhar
Sadece meraktan, bu strateji modelinden farklı mıdır? Bu model algoritmaları kapsüllemekte ve onları birbirleriyle değiştirebilmektedir. Bağımlılık enjeksiyonu gibi hissediyor ve strateji modelleri çok benzer. - elixir


"Bağımlılık enjeksiyonu", sadece parametreli kurucular ve kamu belirleyicileri kullanmak anlamına gelmez mi?

James Shore'ın makalesinde karşılaştırma için aşağıdaki örnekler gösterilmektedir..

Bağımlılık yapılmayan kurucu:

public class Example { 
  private DatabaseThingie myDatabase; 

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

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

Bağımlılık enjeksiyonlu kurucu:

public class Example { 
  private DatabaseThingie myDatabase; 

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

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

45
2018-05-02 00:40



Kesinlikle DI sürümünde hiçbir argüman yapıcıda myDatabase nesnesini başlatmak istemezsiniz? DoStuff'u aşırı yüklü kurucuyu aramadan aramaya kalkarsanız, bir noktaya yer vermez ve bir istisna atmaya hizmet eder miydi? - Matt Wilko
Yalnızca new DatabaseThingie() geçerli bir myDatabase örneği oluşturmuyor. - JaneGoodall


Bağımlılık Enjeksiyonu Nedir?

Diğerleri dediği gibi, Bağımlılık Enjeksiyonu (DI) doğrudan yaratımın sorumluluğunu ve yaşam süresinin yönetimini, bizim ilgi alanımızın (tüketici sınıfı) bağımlı olduğu diğer nesne örneklerinin çıkarır. UML duygusu). Bu örnekler bunun yerine tüketici sınıfımıza, tipik olarak yapıcı parametreleri veya özellik belirteçleri aracılığıyla iletilir (bağımlılık nesnesinin yönetimi ve tüketici sınıfına geçişi genellikle bir Kontrolün Tersine Çevirilmesi (IoC) konteyner, ama bu başka bir konu).

DI, DIP ve KATI

Özellikle, Robert C Martin'in paradigmasında Nesneye Yönelik Tasarımın Katı İlkeleri, DI olası uygulamalardan biridir Bağımlılık İnversiyon Prensibi (DIP). DIP D arasında SOLID mantra  - Diğer DIP uygulamaları Servis Konumlandırıcı ve Eklenti kalıplarını içerir.

DIP'nin amacı, sınıflar arasındaki sıkı, somut bağımlılıkları ayırmak ve bunun yerine, birleştirme yoluyla elde edilebilecek bir soyutlama yoluyla kuplajı gevşetmektir. interface, abstract class veya pure virtual class, kullanılan dile ve yaklaşıma bağlı olarak.

DIP olmadan, kodumuz (bu 'tüketici sınıfı' olarak adlandırılır) doğrudan somut bir bağımlılığa bağlıdır ve bu bağımlılığın bir örneğini, yani kavramsal olarak nasıl elde edeceğini ve yöneteceğini bilme sorumluluğuna da sık sık yüklenir:

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

DIP'nin uygulanmasından sonra, gereksinim gevşetilir ve yaşam süresinin elde edilmesi ve yönetilmesi endişesi. Foo bağımlılık kaldırıldı:

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

DIP (ve DI) neden kullanılır?

Bu şekilde sınıflar arasındaki bağımlılıkları ayırma kolay ikame Bu bağımlılık sınıflarının, soyutlamanın ön koşullarını da yerine getiren diğer uygulamalarla (örneğin, bağımlılık aynı arayüzün başka bir uygulaması ile değiştirilebilir). Dahası, diğerlerinin de belirttiği gibi  DIP anahtarı üzerinden sınıfları ayrıştırmak için en yaygın nedeni bir tüketim 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 bir sonucu bağımlılık nesne artık (yapıcı veya ayarlayıcı enjeksiyon yoluyla) tüketici sınıfının geçirilir; bağımlılık nesne örnekleri ömrü yönetimi artık, bir tüketici sınıfının tarafından kontrol edilmesidir.

Bu farklı şekillerde görülebilir:

  • tüketim sınıfı tarafından bağımlılıkları ömrü kontrolü muhafaza edilmesi gerekiyorsa, kumandalı tüketici sınıfa, bağımlılık sınıf örneklerini oluşturmak için (soyut) fabrika enjekte ederek yeniden kurulabilir. Tüketici, Create Gerektiğinde fabrikada, bu örnekleri bir kez tamamlayın.
  • Ya da, bağımlılık örneklerinin ömür boyu kontrolü, bir IoC konteynerine bırakılabilir (aşağıda daha fazlası).

DI ne zaman kullanılır?

  • Eşdeğer bir uygulama için bir bağımlılığın yerine getirilmesinin gerekeceği durumlarda,
  • Üniteye ihtiyaç duyacağınız her zaman, bir sınıfın yöntemlerini, bağımlılıklarını izole ederek test etmek,
  • Bir bağımlılığın yaşam süresinin belirsizliği, denemeyi gerektirebilir (örn. Hey, MyDepClass iş parçacığı güvenlidir - ne yaparsak onu tekil yaparsak ve aynı örneği tüm tüketicilere enjekte edersek?)

Örnek

İşte basit bir C # uygulaması. Aşağıdaki Tüketim 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, iki tane var static diğer iki sınıfa bağımlılık System.DateTime ve System.ConsoleSadece günlük çıkış seçenekleri sınırlamaz hangi (konsola giriş kimse izliyor eğer değersiz olacaktır), ama daha kötüsü, deterministik olmayan bir sistem saatinin bağımlılık verilen otomatik test etmek zordur.

Ancak uygulayabiliriz DIP Bu sınıfa, zaman damgasının bağımlılık olarak kaygısını ve birleştirme MyLogger sadece basit bir arayüze:

public interface IClock
{
    DateTime Now { get; }
}

Ayrıca bağımlılığı da gevşetebiliriz Console bir soyutlamaya TextWriter. Bağımlılık Enjeksiyon tipik olarak ya constructor enjeksiyon (tüketen bir sınıfın yapıcısı için bir parametre olarak bir bağımlılığa bir soyutlama geçirerek) veya Setter Injection (bağımlılığı bir setXyz() ayarlayıcı veya bir Net Özellik ile {set;} tanımlanmıştır). Oluşturucu Enjeksiyon tercih edilir, çünkü bu, yapımdan sonra sınıfın doğru bir durumda olacağını garanti eder ve iç bağımlılık alanlarının işaretlenmesini sağlar. readonly (C #) veya final (Java). Yukarıdaki örnekte kurucu enjeksiyonu kullanarak, bu bizi şu şekilde 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);
    }
}

(Bir beton Clock Sağlanması gereken, tabi ki DateTime.Nowve iki bağımlılığın kurucu enjeksiyon yoluyla bir IoC konteyneri tarafından sağlanması gerekir.

Logger'ımızın doğru bir şekilde çalıştığını kesin olarak kanıtlayan otomatik bir Birim Testi oluşturulabilir, çünkü artık bağımlılıklar üzerinde kontrol sahibi olduğumuz - zaman ve yazılı çıktıda casusluk yapabiliriz:

[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 her zaman bir Kontrol kabının ters çevrilmesi (IoC)somut bağımlılık örneklerini enjekte etmek (sağlamak) ve yaşam koşullarını yönetmek için. Yapılandırma / önyükleme işlemi sırasında, IoC kaplar aşağıdakilerin tanımlanmasını sağlar:

  • her bir soyutlama ve yapılandırılmış beton uygulaması arasında haritalama (ör. "Bir tüketici istediği zaman IBar, geri dön ConcreteBar örneğin")
  • Her bağımlılığın ömür boyu yönetimi için politikalar oluşturulabilir, örn. Her tüketici örneği için yeni bir nesne oluşturmak, tüm tüketicilere tek bir bağımlılık örneğini paylaşmak, aynı bağımlılık örneğini yalnızca aynı iş parçacığıyla paylaşmak vb.
  • .Net, IoC kapsayıcılar gibi protokollerin farkındadır IDisposable ve sorumluluğunu üstlenecek Disposing yapılandırılmış ömür yönetimi ile bağlantılı olarak bağımlılıklar.

Tipik olarak, IoC konteynerleri yapılandırıldığında / önyüklendiğinde, kodlayıcıya bağımlılıkları endişe etmekten ziyade kod üzerinde odaklanmasına olanak tanıyan arka planda kesintisiz olarak çalışırlar.

DI-dostu kodun anahtarı, sınıfların statik bağlanmasını önlemek ve Bağımlılıkların oluşturulması için yeni () kullanmamaktır.

Yukarıdaki örneğe göre, bağımlılıkların ayrıştırılması bazı tasarım çabaları gerektirmektedir ve geliştirici için, alışkanlıktan kurtulmak için gerekli bir paradigma değişimi vardır. newBağımlılıkları doğrudan bağlayıp bağımlılıkları yönetmek için konteynere güvenmek yerine.

Ancak faydaları, özellikle ilgi alanınızı kapsamlı bir şekilde test etme becerisinde.

Not : Yaratılış / haritalama / projeksiyon (üzerinden) new ..()) POCO / POJO / Serileştirme DTO'ları / Varlık Grafikleri / Anonim JSON projeksiyonları ve al - i.e. "Yalnızca veri" sınıfları veya kayıtlar - yöntemlerden veya kullanılan yöntemler değil Bağımlılıklar olarak kabul edildi (UML anlamında) ve DI'ye tabi değildir. kullanma new Bunları yansıtmak sadece iyi.


34
2018-04-28 20:17



Sorun DIP! = DI. DIP, soyutlamayı uygulamadan ayırmakla ilgilidir: A. Yüksek düzeyli modüller düşük seviyeli modüllere bağlı olmamalıdır. Her ikisi de soyutlamalara dayanmalıdır. B. Soyutlamalar ayrıntılara bağlı olmamalıdır. Ayrıntılar soyutlamalara bağlı olmalıdır. DI, nesne kullanımından nesne oluşturmayı ayırmanın bir yoludur. - Ricardo Rivaldo
Evet, paragraf 2'de ayrım açıkça belirtilmiştir. "DIP'nin olası uygulamalarından biri DI", Bob Amca'nın SOLID paradigmasında. Bunu da yaptım açık önceki bir yazıda. - StuartLC