Bağımlılık Enjeksiyonu kullanmanın olumsuz yanları nelerdir? [kapalı]


336

Ben iş yerinde bir desen olarak DI tanıtmak çalışıyorum ve bizim öncü geliştiricilerden biri bilmek istiyorum: Ne - varsa - Bağımlılık Enjeksiyon desen kullanmanın dezavantajları nelerdir?

Not Burada konuyla ilgili öznel bir tartışma değil, mümkünse kapsamlı bir liste arıyorum.


Açıklama : XML tabanlı (Spring gibi) veya kod tabanlı (Guice gibi) veya "kendi kendine yuvarlanan" özel bir çerçeveden değil , Bağımlılık Enjeksiyon kalıbından ( Martin Fowler'ın bu makalesine bakın) bahsediyorum. .


Düzenleme : Bazı büyük tartışma / sıralama / tartışma oluyor / r / programlama burada.


DI'nin kendisini mi yoksa onu destekleyen belirli bir araç türünü mi (XML tabanlı veya değil) tartışmamız gerektiğini belirtmek iyi bir fikir olabilir.
Jesse Millikan

5
fark sadece "XML berbat" gibi belirli çerçeveler için geçerli olan cevapları ARAMAM. :) Ben burada Fowler tarafından belirtilen DI kavramı için geçerli cevaplar arıyorum: martinfowler.com/articles/injection.html
Epaga

3
Genel olarak DI için hiçbir dezavantajı görmüyorum (yapıcı, ayarlayıcı veya yöntem). Tepegöz olmadan ayrışır ve basitleştirir.
Kissaki

2
@kissaki setter enjekte şeyler dışında iyi. İnşaatta kullanılabilir nesneleri yapmak için en iyisi. Bana inanmıyorsanız, sadece 'setter' enjeksiyonu ile bir nesneye başka bir ortak çalışan eklemeyi deneyin, kesin bir NPE alacaksınız ....
time4tea

Yanıtlar:


209

Birkaç nokta:

  • DI, sorumlulukları daha fazla ayrıldığından, genellikle sınıf sayısını artırarak karmaşıklığı arttırır, bu da her zaman yararlı değildir
  • Kodunuz (bir şekilde) kullandığınız bağımlılık enjeksiyon çerçevesine (ya da daha genel olarak DI modelini uygulamaya nasıl karar vereceğinize) bağlı olacaktır.
  • Tip çözme yapan DI kapları veya yaklaşımları genellikle hafif bir çalışma süresi cezasına neden olur (çok ihmal edilebilir, ancak orada)

Genel olarak, ayırmanın yararı, her görevin okunmasını ve anlaşılmasını kolaylaştırır, ancak daha karmaşık görevleri düzenlemenin karmaşıklığını artırır.


72
- Sınıfların ayrılması karmaşıklığı azaltır. Birçok sınıf bir uygulamayı karmaşık hale getirmez. - Yalnızca uygulama kökündeki DI çerçevenize bağımlı olmalısınız.
Robert

91
Biz insanız; kısa süreli belleğimiz sınırlıdır ve aynı anda birçok <xxx> işleyemez. Sınıflar için, yöntemler, işlevler, dosyalar veya programınızı geliştirmek için kullandığınız herhangi bir yapı için olduğu gibi aynıdır.
Håvard S

45
@Havard S: Evet, ancak 5 gerçekten karmaşık sınıf 15 basit sınıftan daha basit değil. Karmaşıklığı azaltmanın yolu, kod üzerinde çalışan programcının gerektirdiği çalışma kümesini azaltmaktır - karmaşık, birbirine bağımlı sınıflar bunu başaramaz.
kyoryu

35
@kyoryu Sanırım hepimiz buna katılıyoruz. Karmaşıklığın kuplajla aynı olmadığını unutmayın . Bağlantının azaltılması karmaşıklığı artırabilir. Gerçekten DI kötü bir şey olduğunu söylemiyorum çünkü sınıf sayısını artırır, onunla ilişkili potansiyel olumsuz yanlarını vurgulamak. :)
Håvard S

96
"DI karmaşıklığı artırır" için +1 DI ve ötesinde geçerlidir. (Neredeyse) esnekliği her arttırdığımızda, karmaşıklığı artıracağız. Her şey, yukarı ve aşağı tarafları bilmekle başlayan denge ile ilgilidir. İnsanlar 'hiçbir dezavantaj yok' dediğinde, bu şeyi henüz tam olarak anlamadıklarının kesin bir göstergesi.
Don Branson

183

Nesne yönelimli programlama, stil kuralları ve hemen hemen her şeyle ilgili sık karşılaştığınız temel sorun. Çok yaygın soyutlama yapmak ve çok fazla dolaylılık eklemek ve genellikle iyi teknikleri aşırı ve yanlış yerlerde uygulamak mümkündür.

Uyguladığınız her desen veya diğer yapı karmaşıklık getirir. Soyutlama ve dolaylı bilgi etrafa saçılır, bazen alakasız ayrıntıları yoldan çıkarır, ancak eşit olarak bazen neler olduğunu tam olarak anlamayı zorlaştırır. Uyguladığınız her kural, en iyi yaklaşım olabilecek seçenekleri göz ardı ederek esneklik getirir.

Mesele, işi yapan, sağlam, okunabilir ve bakımı kolay kod yazmaktır. Siz bir yazılım geliştiricisiniz - fildişi kule üreticisi değil.

İlgili Bağlantılar

http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx

http://www.joelonsoftware.com/articles/fog0000000018.html


Muhtemelen en basit bağımlılık enjeksiyon şekli (gülmeyin) bir parametredir. Bağımlı kod verilere bağlıdır ve bu veri parametrenin geçirilmesi yoluyla enjekte edilir.

Evet, aptalca ve nesneye yönelik bağımlılık enjeksiyonuna değinmiyor, ancak işlevsel bir programcı size (birinci sınıf işlevleriniz varsa) ihtiyacınız olan tek tür bağımlılık enjeksiyonu olduğunu söyleyecektir. Buradaki nokta önemsiz bir örnek almak ve olası sorunları göstermek.

Bu basit geleneksel işlevi ele alalım - C ++ sözdizimi burada önemli değil, ama bir şekilde hecelemek zorundayım ...

void Say_Hello_World ()
{
  std::cout << "Hello World" << std::endl;
}

Ben "Merhaba Dünya" metni ayıklamak ve enjekte etmek istiyorum bir bağımlılık var. Yeterince kolay...

void Say_Something (const char *p_text)
{
  std::cout << p_text << std::endl;
}

Bu orijinalden daha esnek değil mi? Peki ya çıktının unicode olması gerektiğine karar verirsem. Muhtemelen std :: cout'tan std :: wcout'a geçmek istiyorum. Ama bu benim dizeleri char değil, wchar_t olması gerektiği anlamına gelir. Ya her çağıranın değiştirilmesi gerekir, ya da (daha makul olarak) eski uygulama, dizeyi çeviren bir adaptör ile değiştirilir ve yeni uygulamayı çağırır.

Bu, orijinali tutsaydık, gerekli olmayacak bakım işi.

Ve önemsiz görünüyorsa, Win32 API'den bu gerçek dünya işlevine bir göz atın ...

http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx

Bu 12 "bağımlılık" ile başa çıkmak. Örneğin, ekran çözünürlükleri gerçekten çok büyük olursa, 64 bit koordinat değerlerine ve CreateWindowEx'in başka bir sürümüne ihtiyacımız olabilir. Ve evet, hala asılı olan eski bir sürüm var, muhtemelen sahnelerin arkasındaki yeni sürüme eşleştiriliyor ...

http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx

Bu "bağımlılıklar" sadece orijinal geliştirici için bir sorun değildir - bu arayüzü kullanan herkes bağımlılıkların ne olduğunu, nasıl belirtildiklerini ve ne anlama geldiklerini araştırmalı ve uygulamaları için ne yapmaları gerektiğini incelemelidir. Burası "mantıklı temerrüt" kelimelerinin hayatı çok daha kolaylaştıracağı yerdir.

Nesneye yönelik bağımlılık enjeksiyonu prensipte farklı değildir. Bir sınıf yazmak, hem kaynak kodu metninde hem de geliştirici zamanında bir ek yüktür ve bu sınıf bazı bağımlı nesne özelliklerine göre bağımlılıklar sağlamak için yazılırsa, bağımlı nesne, bir gereksinim olsa bile bu arabirimi desteklemeye kilitlenir o nesnenin uygulanmasını değiştirmek.

Bunların hiçbiri bağımlılık enjeksiyonunun kötü olduğunu iddia etmek olarak okunmamalıdır. Ancak herhangi bir iyi teknik aşırı ve yanlış yerde uygulanabilir. Her dizenin çıkarılması ve bir parametreye dönüştürülmesi gerekmediği gibi, her düşük seviyeli davranışın da üst düzey nesnelerden çıkarılması ve enjekte edilebilir bir bağımlılığa dönüştürülmesi gerekmez.


3
Bağımlılık enjeksiyonunun bu dezavantajları yoktur. Yalnızca nesnelere geçiş bağımlılığınızın şeklini değiştirir, bu da karmaşıklık veya esneklik katmaz. Aksine.
Kissaki

24
@Kissaki - evet, bağımlılıklarınızı geçirme şeklinizi değiştirir. Ve bağımlılıkların bu geçişi ile başa çıkmak için kod yazmalısınız. Bunu yapmadan önce, hangi bağımlılıkların geçeceğini hesaplamanız, bunları bağımlı kodu kodlamayan birine anlamlı bir şekilde tanımlamanız gerekir. Vb. Çalışma zamanı etkisinden kaçınabilirsiniz (örn. Şablonlara ilke parametreleri kullanma) C ++), ancak yine de yazmanız ve bakım yapmanız gereken kod. Eğer haklıysa, büyük bir ödül için çok küçük bir bedeldir, ancak ödeyecek bir bedel varsa, bu sadece kazanç olmadığında bu fiyatı ödeyeceğiniz anlamına gelir.
Steve314

6
@Kissaki - esnek olmayanlara gelince, bağımlılıklarınızın ne olduğunu belirledikten sonra, buna kilitlenirsiniz - diğer insanlar bu spesifikasyona göre enjekte etmek için bağımlılıklar yazmışlardır. Bağımlı kod için biraz farklı bağımlılıklara ihtiyaç duyan yeni bir uygulamaya ihtiyacınız varsa - zor, kilitli durumdasınız. Bu bağımlılıklar için bazı adaptörler yazmaya başlama zamanı (ve biraz daha fazla yük ve başka bir soyutlama katmanı).
Steve314

Aşırı yüklemeyi düşünüyorsanız, bu örneği anladığımdan emin değilim. Değişmez "Merhaba Dünya" çıktısını almak için, () imzasını kullanırız. 8 bit dize çıktısı almak için, (char) imzasını kullanın. Unicode çıktısı için aşırı yük (wchar_t). Açıkçası, bu durumda, (wchar_t) diğerlerinin perde arkasında çağırdığı oyundur. Orada fazla kod yeniden yazılmasına gerek yok. Bir şey mi kaçırıyorum?
ingredient_15939

2
@ material_15939 - evet, bu basitleştirilmiş bir oyuncak örneğidir. Bunu gerçekten yapıyorsanız, kodu çoğaltma maliyeti adaptörün maliyetinden daha az olduğundan, bir adaptör yerine sadece aşırı yükleme kullanırsınız. Ancak, kodun çoğaltılmasının genellikle kötü bir şey olduğunu ve kodun kopyalanmasını önlemek için adaptörlerin kullanılmasının başka bir iyi teknik olduğunu unutmayın (bazen çok fazla ve yanlış yerlerde kullanılabilir).
Steve314

77

İşte benim ilk tepkim: Temelde herhangi bir modelin aynı dezavantajları.

  • öğrenmek zaman alır
  • eğer yanlış anlaşılırsa faydadan çok zarara yol açabilir
  • Eğer aşırıya kaçarsa, faydayı haklı çıkaracağından daha fazla iş olabilir

2
Öğrenmek neden zaman alıyor? Ben ejb ile karşılaştırıldığında işleri kolaylaştırdığını düşündüm.
fastcodejava

8
Sübjektif bir tartışma istemediğiniz düşünüldüğünde bu dalgalı görünüyor. İnceleme için gerçekçi bir örnek oluşturmayı (gerekirse toplu olarak) öneririm. DI'siz bir örnek oluşturmak iyi bir başlangıç ​​noktası olacaktır. Sonra gereksinim değişikliklerine meydan okuyabilir ve etkisini inceleyebiliriz. (Bu benim önermek benim için son derece uygun, bu arada, yatağa gitmek üzereyim.)
Jesse Millikan

4
Bu, onu desteklemek için gerçekten bazı örneklere ihtiyaç duyuyor ve düzinelerce insana öğretti DI Size, öğrenmenin ve uygulamaya başlamanın gerçekten çok basit bir kavram olduğunu söyleyebilirim.
chillitom

4
Gerçekten DI'yi bir örüntü olarak görmüyorum. O (IoC ile birleştiğinde) gerçekten bir programlama modelidir - eğer onları tam olarak takip ederseniz, kodunuz "tipik" sözde prosedür OO'sundan çok daha Aktör benzeri görünür.
kyoryu

1
+1 Ben Symfony 2 kullanıyorum, DI kullanıcı kodu her yerinde, sadece onu kullanarak exausting.
MGP

45

İnversiyon Kontrolün en büyük "dezavantajı" (tam olarak DI değil, ancak yeterince yakın), bir algoritmaya genel bakışa bakmak için tek bir noktaya sahip olma eğilimindedir. Bununla birlikte, temelde kodu çözdüğünüzde olan şey budur - tek bir yere bakma yeteneği sıkı bir bağlantının eseridir.


2
Ama şüphesiz ki "dezavantajı" çözdüğümüz sorunun doğasından kaynaklanmaktadır, böylece uygulamayı kolayca değiştirebiliriz, bakılacak tek bir yer olmadığı anlamına gelir ve bakabilmek için ne önemi var? Düşünebildiğim tek durum hata ayıklama ve hata ayıklama ortamının uygulamaya geçebilmesi.
vickirk

3
"Dezavantajı" kelimesinin tırnak içinde olmasının nedeni budur :) Gevşek birleştirme ve güçlü kapsülleme "her şeyi görmek için bir yer" türünü engellemez. DI / IoC'a karşı olduğumu hissederseniz Havard S'nin yanıtı hakkındaki yorumlarıma bakın.
kyoryu

1
Kabul ediyorum (hatta sana oy verdim). Sadece konuya değindim.
vickirk

1
@vickirk: Sanırım olumsuz tarafı, bir insanın kavramasının zor olmasıdır. Bir şeyleri ayırmak, insanların anlaması daha zor olduğu ve tam olarak anlaşılması daha uzun sürdüğü için karmaşıklığı artırır.
Bjarke Freund-Hansen

2
Aksine, DI'nin bir avantajı, bireysel bir sınıfın yapıcısına bakabilmeniz ve hangi sınıflara bağlı olduğunu (yani sınıfların işini yapması gereken) anında çalışabilmenizdir. Bu kod diğer kodlar için çok daha zordur, çünkü kod willy-nilly sınıfları oluşturabilir.
Contango

42

7
Merak ediyorum, birisi wonsides istediğinde, neden bir ruh içinde cevaplar var "sorusu yok" ve soruyla ilgili bazı bilgiler içerenler yok?
Gabriel Ščerbák

12
-1 çünkü bir bağlantı koleksiyonu aramıyorum, gerçek cevaplar arıyorum: her makalenin puanlarını özetlemeye ne dersiniz? Sonra yerine vekalet ediyorum. İlk iki aslında DI olumsuzluklarını debunking görünüyor olsa da makalelerin kendileri oldukça ilginç olduğunu unutmayın?
Epaga

4
En çok oylanan cevabın da aşağıya inip varamadığını merak ediyorum, çünkü bu gerçekten soruyu hiç cevaplamıyor imho :) Tabii ne sorduğunuzu ve ne cevap verdiğimi biliyorum, upvotes istemiyorum, neden sadece benim görünüşe göre DI dezavantajı çok havalı olduğunu söylerken çok yardımcı oluyor.
Gabriel Ščerbák

41

Son 6 aydır Guice (Java DI framework) kullanıyorum. Genel olarak harika olduğunu düşünüyorum (özellikle bir test açısından), bazı dezavantajları vardır. En önemlisi:

  • Kodun anlaşılması zorlaşabilir. Bağımlılık enjeksiyonu çok ... yaratıcı ... yollarla kullanılabilir. Örneğin, belirli bir IOStreams'i enjekte etmek için özel bir açıklama kullanan bazı kodlarla karşılaştım (örneğin: @ Server1Stream, @ Server2Stream). Bu işe yarıyor olsa da ve itiraf edeyim ki belli bir zarafeti var, Guice enjeksiyonlarını anlamak kodu anlamak için bir ön koşul haline getiriyor.
  • Proje öğrenirken daha yüksek öğrenme eğrisi. Bu konu 1 ile ilgilidir. Bağımlılık enjeksiyonunu kullanan bir projenin nasıl çalıştığını anlamak için hem bağımlılık enjeksiyon desenini hem de spesifik çerçeveyi anlamanız gerekir. Mevcut işime başladığımda, Guice'nin perde arkasında neler yaptığını söyleyerek oldukça karışık saatler geçirdim.
  • Yapıcılar büyür. Her ne kadar bu büyük ölçüde varsayılan bir kurucu veya fabrika ile çözülebilir.
  • Hatalar gizlenebilir. Bunun en son örneğim 2 bayrak isminde bir çarpışma yaşadım. Guice hatayı sessizce yuttu ve bayraklarımdan biri başlatılmadı.
  • Hatalar çalışma süresine gönderilir. Guice modülünüzü yanlış yapılandırırsanız (dairesel referans, hatalı ciltleme, ...) derleme sırasında hataların çoğu ortaya çıkarılmaz. Bunun yerine, program gerçekten çalıştırıldığında hatalar ortaya çıkar.

Şimdi şikayet ettim. Şunu söyleyeyim ki şu anki projemde ve büyük olasılıkla bir sonraki projemde (isteyerek) Guice kullanmaya devam edeceğim. Bağımlılık enjeksiyonu harika ve inanılmaz derecede güçlü bir kalıptır. Ancak kesinlikle kafa karıştırıcı olabilir ve seçtiğiniz bağımlılık enjeksiyon çerçevesine küfretmek için neredeyse kesinlikle zaman harcayacaksınız.

Ayrıca, diğer posterlere de bağımlılık enjeksiyonunun aşırı kullanılabileceğini kabul ediyorum.


14
İnsanların neden "Hatalar çalışma zamanına itildi" neden daha büyük bir anlaşma yapmadığını anlamıyorum, bu bir anlaşma kırıcı, statik yazım ve derleme zamanı hataları geliştiricilere verilen en büyük hediye, atmazdım bir şey için onları uzakta
Richard Tingle

2
@RichardTingle, uygulama başlatma sırasında IMO ilk olarak başlatılacak, böylece modüldeki tüm yanlış yapılandırmalar birkaç gün veya saatten sonra uygulama başlar başlamaz görünür olacak. Modülleri aşamalı olarak yüklemek de mümkündür, ancak uygulama mantığını başlatmadan önce modül yüklemesini sınırlayarak DI ruhuna sadık kalırsak, kötü bağlamaları uygulamanın başlangıcına başarıyla yalıtabiliriz. Ancak, servis bulucu anti-desen olarak yapılandırırsak, bu kötü bağlamalar kesinlikle bir sürpriz olacaktır.
k4vin

@RichardTingle Derleyici tarafından sağlanan güvenlik ağına asla benzer olmayacağını anlıyorum, ancak kutuda söylendiği gibi doğru kullanılan bir araç olarak DI o zaman bu çalışma zamanı hataları uygulama başlatma ile sınırlıdır. Sonra uygulamanın başlatılmasını DI modülleri için bir tür derleme aşaması olarak görebiliriz. Benim deneyimime göre uygulama başlarsa çoğu zaman kötü bağlamalar veya yanlış referanslar olmayacak. PS - C # ile NInject kullanıyorum
k4vin

@RichardTingle - Seninle aynı fikirdeyim, ama gevşek bağlı, dolayısıyla test edilebilir kodu elde etmek için bir takas. Ve k4vin'in dediği gibi, başlatma sırasında eksik bağımlılıklar bulunur ve arayüzlerin kullanımı derleme zamanı hatalarına yardımcı olacaktır.
Andrei Epure

1
Listenize "Kodu temiz tutmak zor" ifadesini eklerim. Kodu olmadan kapsamlı bir şekilde test etmeden önce bir kaydı silip silemeyeceğinizi asla bilemezsiniz.
fernacolo

24

Herhangi bir DI'siz kod , Spagetti koduna karışmak için bilinen riski taşır - bazı belirtiler, sınıfların ve yöntemlerin çok büyük olması, çok fazla şey yapması ve kolay değiştirilememesi, parçalanmaması, yeniden düzenlenmesi veya test edilmemesidir.

Çok kullanılan DI ile kod , her küçük sınıfın bireysel bir mantı nugget gibi olduğu Ravioli kodu olabilir - küçük bir şey yapar ve tek sorumluluk ilkesine uyulur, ki bu iyidir. Ancak sınıflara kendi başlarına bakmak, sistemin bir bütün olarak ne yaptığını görmek zordur, çünkü bu, tüm bu küçük parçaların birbirine nasıl uyduğuna bağlıdır, bu da zor görülür. Sadece büyük bir yığın küçük şey gibi görünüyor.

Büyük bir sınıf içinde büyük birleştirilmiş kodun büyük bitlerinin spagetti karmaşıklığından kaçınarak, çok sayıda basit küçük sınıfın olduğu ve aralarındaki etkileşimlerin karmaşık olduğu başka bir tür karmaşıklık riskiyle karşı karşıya kalırsınız.

Bunun ölümcül bir dezavantaj olduğunu düşünmüyorum - DI hala çok değerli. Sadece bir şey yapan küçük sınıflarla bir dereceye kadar mantı stili muhtemelen iyidir. Aşırı olsa bile, spagetti kodu kadar kötü olduğunu düşünmüyorum. Ancak çok ileri götürülebileceğinin farkında olmak, bundan kaçınmanın ilk adımıdır. Nasıl önleneceği hakkında tartışma için bağlantıları takip edin.


1
Evet, "mantı kodu" terimini seviyorum; DI'nin dezavantajı hakkında konuştuğumda daha uzun süre ifade ediyorum. Yine de, DI olmadan Java'da gerçek bir çerçeve veya uygulama geliştirmeyi hayal edemiyorum.
Howard M. Lewis Gemisi,

13

Evde yetiştirilen bir çözümünüz varsa, bağımlılıklar kurucuda yüzünüzde. Ya da belki yine tespit edilmesi çok zor olmayan yöntem parametreleri olarak. Her ne kadar çerçeve tarafından yönetilen bağımlılıklar, aşırı uçlara götürülürse, sihir gibi görünmeye başlayabilir.

Ancak, çok fazla sınıfta çok fazla bağımlılığa sahip olmak, sınıf yapınızın berbat olduğunu gösteren açık bir işarettir. Böylece, bir şekilde bağımlılık enjeksiyonu (evde yetiştirilen veya yönetilen çerçeve) karanlıkta gizlenen gizli tasarım sorunlarının ortaya çıkmasına yardımcı olabilir.


İkinci noktayı daha iyi göstermek için, bu makaleden ( orijinal kaynak ) sadece bilgisayar sistemleri değil, herhangi bir sistem kurmanın temel problemi olduğuna yürekten inanıyorum.

Bir üniversite kampüsü tasarlamak istediğinizi varsayalım. Tasarımın bir kısmını öğrencilere ve profesörlere devretmelisiniz, aksi takdirde Fizik binası fizik insanları için iyi çalışmaz. Hiçbir mimar insanların kendi başlarına yapmaları gereken fizik hakkında yeterince bilgi sahibi değildir. Ancak her odanın tasarımını yolcularına devredemezsiniz, çünkü o zaman dev bir moloz yığını elde edersiniz.

Genel tasarımın tutarlılığını ve uyumunu korurken tasarım sorumluluğunu büyük bir hiyerarşinin tüm düzeylerinde nasıl dağıtabilirsiniz? Bu, Alexander'ın çözmeye çalıştığı mimari tasarım problemidir, ancak aynı zamanda bilgisayar sistemlerinin geliştirilmesinde de temel bir sorundur.

DI bu sorunu çözüyor mu? Hayır . Ancak, her odayı yolcularına tasarlama sorumluluğunu devretmeye çalışıp çalışmadığınızı açıkça görmenize yardımcı olur.


13

DI ile biraz kıvırmamı sağlayan bir şey, enjekte edilen tüm nesnelerin somutlaştırılması ve hiçbir yan etki üretmemesinin ucuz olduğu varsayımıdır -VEYA- bağımlılık o kadar sık ​​kullanılır ki ilişkili herhangi bir örnekleme maliyetinden daha ağır basar.

Bunun önemli olduğu yerlerde, bağımlılık tüketen bir sınıfta sık kullanılmadığında; gibi bir şey IExceptionLogHandlerService. Açıkçası, böyle bir hizmet (umarım :)) sınıf içinde nadiren çağrılır - muhtemelen sadece günlüğe kaydedilmesi gereken istisnalar üzerine; yine de kanonik kurucu enjeksiyon paterni ...

Public Class MyClass
    Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService

    Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
        Me.mExLogHandlerService = exLogHandlerService
    End Sub

     ...
End Class

... bu hizmetin "canlı" bir örneğinin sunulmasını gerektirir, oraya ulaşmak için gereken maliyet / yan etkilere zarar verir. Muhtemelen değil, ama ya bu bağımlılık örneğini oluşturmak bir hizmet / veritabanı isabeti içeriyorsa veya dosya aramaları yapılandırıyorsa veya imha edilene kadar bir kaynağı kilitlerse ne olacak? Bu hizmet bunun yerine gerektiğinde, hizmete yerleştirilmiş veya fabrikada oluşturulmuşsa (hepsi kendi sorunlarına sahipse), inşaat maliyetini yalnızca gerektiğinde almanız gerekir.

Şimdi, bir nesneyi kurmanın, genel kabul gören bir yazılım tasarımı ilkedir olan ucuz ve gelmez yan etkiler üretmek. Ve bu güzel bir kavram olsa da, her zaman böyle değildir. Bununla birlikte, tipik yapıcı enjeksiyonunun kullanılması temelde durumun böyle olmasını gerektirir. Bir bağımlılık uygulaması oluşturduğunuzda, bunu DI düşünülerek tasarlamanız gerekir. Belki başka bir yerde fayda elde etmek için nesne yapımını daha maliyetli hale getirirdiniz, ancak bu uygulama enjekte edilecekse, muhtemelen bu tasarımı yeniden düşünmeye zorlarsınız.

Bu arada, bazı teknikler, enjekte edilen bağımlılıkların tembel olarak yüklenmesine izin vererek, örneğin bağımlılık olarak bir sınıf Lazy<IService>örneği sağlayarak bu kesin sorunu hafifletebilir . Bu, bağımlı nesnelerinizin yapıcılarını değiştirir ve daha sonra, istenen bir şekilde arzu edilmeyen, nesne yapımı gideri gibi uygulama ayrıntılarının daha da farkında olmasını sağlar.


1
Ne dediğini anlıyorum, ama "bir bağımlılığın bir uygulamasını oluşturduğunda, bunu DI'yi akılda tutarak tasarlamalısın" demenin adil olduğunu düşünmüyorum - bence daha doğru bir ifade "DI çalışır en iyi, örnekleme maliyeti ve inşaat sırasında yan etkilerin veya arıza modlarının eksikliğine ilişkin en iyi uygulamalarla uygulanan sınıflarla kullanıldığında ". En kötü durumda, her zaman ilk nesneye kadar gerçek nesnenin tahsisini savunan tembel bir proxy uygulaması enjekte edebilirsiniz.
Jolly Roger

1
Herhangi bir modern IoC kapsayıcısı, belirli bir soyut tür / arabirim (her zaman benzersiz, singleton, http kapsamındaki vb.) İçin bir nesnenin ömrünü belirtmenize olanak tanır. Ayrıca Func <T> veya Lazy <T> kullanarak tembel bir şekilde başlatmak için bir fabrika yöntemi / temsilci de sağlayabilirsiniz.
Dmitry S.

Açık. Bağımlılıkları başlatmak gereksiz yere belleğe mal olur. Normalde "tembel yükleme" yi yalnızca çağrıldığında bir sınıfı başlatan alıcılarla kullanırım. Parametreleri olmayan bir kurucuyu ve somutlaştırılmış bağımlılıkları kabul eden müteakip kurucuları varsayılan olarak sağlayabilirsiniz. İlk durumda, örneğin IErrorLogger uygulayan bir sınıf yalnızca this.errorLogger.WriteError(ex)try / catch deyiminde bir hata oluştuğunda başlatılır .
John Bonfardeci

12

Kodunuzu GERÇEKTEN ayırmadan bağımlılık enjeksiyonu uygulayarak kodunuzu çözdüğünüz yanılsaması. Bence DI ile ilgili en tehlikeli şey bu.


11

Bu daha çok bir nitpick. Ancak bağımlılık enjeksiyonunun dezavantajlarından biri, geliştirme araçlarının kod hakkında akıl yürütmesini ve gezinmesini biraz zorlaştırmasıdır.

Özellikle, koddaki bir yöntem çağrısında Control-Click / Command-Click tuşlarına basarsanız, somut uygulama yerine bir arabirimdeki yöntem bildirimine götürürsünüz.

Bu gerçekten gevşek bağlanmış kodun (arabirim tarafından tasarlanan kod) bir dezavantajıdır ve bağımlılık enjeksiyonu kullanmasanız bile (yani fabrikaları kullansanız bile) geçerlidir. Ancak bağımlılık enjeksiyonunun gelişmesi, kitlelere gevşek bir şekilde bağlanmış kodu gerçekten teşvik eden şeydir, bu yüzden bahsettiğimi düşündüm.

Ayrıca, gevşek bağlı kodun faydaları bundan çok daha ağır basar, bu yüzden buna nitpick diyorum. Bağımlılık enjeksiyonunu uygulamaya çalışırsanız bu tür bir geri itme olduğunu bilmek için yeterince çalıştım.

Aslında, her "olumsuz" için bağımlılık enjeksiyonu için bulabileceğinizi tahmin etmek için girişimde bulunacağım, çok ağır basan birçok yükseliş bulacaksınız.



1
Ama sonra tekrar (ideal bir dünyada) her şeyin en az 2 uygulaması olmaz mıydı, yani en az bir gerçek uygulama ve birim test için sahte bir uygulama ;-)
vickirk

1
Eclipse'de Ctrl tuşunu basılı tutarsanız ve imleci yöntem çağırma kodunun üzerine getirirseniz, size Bildirimi veya Uygulamayı açmak için bir menü gösterilir.
Sam Hasler

Arayüz tanımındaysanız, yöntem adını vurgulayın ve bu yöntem için tür hiyerarşisini getirmek için Ctrl + T tuşlarına basın; bu yöntemin her uygulayıcısını bir tür hiyerarşi ağacında görürsünüz.
qualidafial

10

Yapıcı tabanlı bağımlılık enjeksiyonu (büyülü "çerçeveler" yardımı olmadan) OO kodunu yapılandırmanın temiz ve yararlı bir yoludur. Gördüğüm en iyi kod tabanlarında, Martin Fowler'ın diğer eski meslektaşlarıyla geçen yıllar boyunca, bu şekilde yazılmış en iyi sınıfların tek bir doSomethingyönteme sahip olduğunu fark etmeye başladım .

O zaman büyük dezavantajı, işlevsel programlamanın faydalarını elde etmek için kapakların sınıflar olarak yazılması için sadece uzun bir kludgy OO yolunun farkına vardığınızda, OO kodu yazma motivasyonunuzun hızla buharlaşabileceğidir.


1
Yapıcı tabanlı sorun her zaman daha fazla yapıcı argümanı eklemeniz gerekeceğidir ...
Miguel Ping

1
Haha. Bunu çok fazla yaparsanız, yakında kodunuzun berbat olduğunu göreceksiniz ve yeniden düzenleyeceksiniz. Ayrıca, ctrl-f6 o kadar da zor değil.
time4tea

Ve elbette bunun tersi de geçerlidir: OO programlamanın avantajlarından yararlanmak için sınıfların
kapanış

Yıllar önce Perl'de kapaklar kullanarak bir nesne sistemi inşa ettim, bu yüzden söylediklerinizi elde ediyorum, ancak verileri kapsüllemek OO programlamanın benzersiz bir yararı değil , bu yüzden OO'nun bu yararlı özelliklerinin karşılaştırılabilir olduğu açık değil kludgy ve işlevsel bir dilde elde etmek için uzun süreli.
sanityinc

9

Kurucu enjeksiyon büyük çirkin kurucuları yol açabilir buluyorum, (ve ben benim kod tabanı boyunca kullanın - belki de benim nesneleri çok parçalı?). Ayrıca, bazen yapıcı enjeksiyonu ile korkunç dairesel bağımlılıklar ile sonuçlanırım (bu çok nadir olmasına rağmen), böylece kendinizi daha karmaşık bir sistemde birkaç tur bağımlılık enjeksiyonu ile bir tür hazır durum yaşam döngüsüne sahip olmak zorunda bulabilirsiniz.

Ancak, setter enjeksiyonu üzerine konstrüktör enjeksiyonunu tercih ederim, çünkü nesnem inşa edildikten sonra, şüphesiz hangi durumda olduğunu, bir birim test ortamında mı, yoksa bazı IOC konteynerinde mi yüklü olduğunu biliyorum. Hangi, dolambaçlı bir şekilde, ayarlayıcı enjeksiyon ile ana dezavantajı olduğunu hissediyorum diyor.

(bir sidenote olarak, tüm konuyu oldukça "dini" buluyorum, ancak kilometreniz geliştirici ekibinizdeki teknik zealotry seviyesine göre değişecek!)


8
Büyük çirkin kurucularınız varsa, sınıflarınız büyük olabilir ve sadece çok bağımlılıklarınız mı var?
Robert

4
Bu kesinlikle eğlendirmek istediğim bir olasılıktır! ... Ne yazık ki, yine de akran değerlendirmeleri yapabileceğim bir ekibim yok. keman arka planda yumuşakça oynamak ve daha sonra ekran siyaha kaybolur ...
James B

1
Mark Seeman üzgün "kariyeriniz için tehlikeli olabilir ..."
Robert

Burada bu kadar etkileyici olabileceğine dair hiçbir ipucu arka plan anlatımım yoktu: P
Anurag

@Robert Alıntıyı bulmaya çalışıyorum, yukarıda nerede söyledi?
liang

8

Bir IOC kabı olmadan DI kullanıyorsanız, en büyük dezavantajı, kodunuzun gerçekte kaç bağımlılığa sahip olduğunu ve her şeyin gerçekten ne kadar sıkı bir şekilde eşleştiğini hızlı bir şekilde görmenizdir. ("Ama bunun iyi bir tasarım olduğunu düşündüm!") Doğal ilerleme, öğrenmek ve uygulamak için biraz zaman alabilen bir IOC konteynerine doğru hareket etmektir (WPF öğrenme eğrisi kadar kötü değil, ancak ücretsiz değil) ya da). Son dezavantajı, bazı geliştiricilerin iyilik birimi testlerine dürüst yazmaya başlayacağı ve bunları anlamaları zaman alacaktır. Daha önce yarım gün içinde bir şey krank edebilecek geliştiriciler aniden iki gün geçirerek tüm bağımlılıklarını nasıl alay edeceklerini anlamaya çalışacaklar.

Mark Seemann'ın cevabına benzer şekilde, sonuçta, kod parçalarını birlikte kesmek ve kapıdan dışarıya / üretime atmak yerine daha iyi bir geliştirici olmak için zaman harcamanızdır. İşletmeniz hangisini tercih eder? Bunu sadece sen cevaplayabilirsin.


İyi bir nokta. Bu kötü kalite / hızlı teslimat vs kaliteli / yavaş teslimat. Olumsuz tarafı? DI sihir değildir, olmasını beklemek dezavantajdır.
liang

5

DI bir teknik veya örüntüdür ve hiçbir çerçeveyle ilgili değildir. Bağımlılıklarınızı manuel olarak bağlayabilirsiniz. DI, SR (Tek sorumluluk) ve SoC (endişelerin ayrılması) konusunda size yardımcı olur. DI daha iyi bir tasarıma yol açar. Benim bakış açımdan ve deneyimimden hiçbir dezavantajı yok . Diğer desenlerde olduğu gibi, yanlış anlayabilir veya yanlış kullanabilirsiniz (ancak DI durumunda ne olduğunu oldukça zor).

DI'yi eski bir uygulamaya ilke olarak tanıtırsanız, bir çerçeve kullanarak - yapabileceğiniz tek büyük hata, bunu bir Servis-Yer Belirleyicisi olarak kötüye kullanmaktır. DI + Framework kendisi harika ve gördüğüm her yerde işleri daha iyi hale getirdim! Örgütsel açıdan, her yeni süreç, teknik, desen, ... ile ilgili ortak sorunlar vardır:

  • Takımını eğitmelisin
  • Başvurunuzu değiştirmeniz gerekir (riskler dahil)

Genel olarak zaman ve para yatırmak zorundasınız , bunun yanında, gerçekten dezavantaj yok, gerçekten!


3

Kod okunabilirliği. Bağımlılıklar XML dosyalarında gizlendiğinden kod akışını kolayca anlayamazsınız.


9
Bağımlılık enjeksiyonu için XML yapılandırma dosyaları kullanmanıza gerek yoktur - koddaki yapılandırmayı destekleyen bir DI kapsayıcısı seçin.
Håvard S

8
Bağımlılık enjeksiyonu mutlaka XML dosyaları anlamına gelmez. Bu hala Java'da durum böyle olabilir, ancak .NET'te yıllar önce bu bağlantıyı bıraktık.
Mark Seemann

6
Veya hiç DI kabı kullanmayın.
Jesse Millikan

kodun DI kullandığını biliyorsanız, bağımlılıkları kimin ayarladığını kolayca tahmin edebilirsiniz.
Bozho

Java'da, Google'ın Guice uygulamasının XML dosyalarına ihtiyacı yoktur.
Epaga

2

İki şey:

  • Yapılandırmanın geçerli olup olmadığını kontrol etmek için ekstra araç desteği gerektirirler.

Örneğin, IntelliJ (ticari sürüm), bir Spring yapılandırmasının geçerliliğini denetleme desteğine sahiptir ve yapılandırmadaki tür ihlalleri gibi hataları işaretler. Bu tür bir araç desteği olmadan, testleri çalıştırmadan önce yapılandırmanın geçerli olup olmadığını kontrol edemezsiniz.

Bu, 'kek' şablonunun (Scala topluluğu tarafından bilindiği gibi) iyi bir fikir olmasının bir nedenidir: bileşenler arasındaki kablolama tip kontrolörü tarafından kontrol edilebilir. Ek açıklamalarla veya XML ile bu avantajınız yok.

  • Programların küresel statik analizini çok zorlaştırır.

Spring veya Guice gibi çerçeveler, kap tarafından oluşturulan nesne grafiğinin nasıl görüneceğini statik olarak belirlemeyi zorlaştırır. Kapsayıcı başlatıldığında bir nesne grafiği oluştursalar da, yaratılacak / oluşturulacak / oluşturulacak nesne grafiğini tanımlayan yararlı API'ler sağlamazlar.


1
Bu mutlak boğa. Bağımlılık enjeksiyonu bir kavramdır, zorlu bir çerçeve gerektirmez. Tek ihtiyacınız olan yeni. Hendek yayı ve tüm bu saçmalıklar, o zaman araçlarınız iyi çalışacak, ayrıca kodunuzu çok daha iyi yeniden düzenleyebileceksiniz.
time4tea

Doğru, iyi bir nokta. Desenden değil DI çerçevelerindeki problemlerden bahsettiğimden daha açık olmalıydım. Ben cevap zaman (o zaman orada olduğunu varsayarak) soruya açıklamayı kaçırmış olabilir.
Martin Ellis

Ah. Bu durumda rahatsızlığımı mutlu bir şekilde geri çekiyorum. özürlerimi.
time4tea

2

Statik yazım etrafında sürekli olarak teknikler kullandığınızda statik olarak yazılan bir dilin varsayılan faydaları önemli ölçüde azalıyor gibi görünüyor. Röportaj yaptığım büyük bir Java mağazası, yapı bağımlılıklarını, etkili olabilmesi için tüm Spring dosyalarını ayrıştırmak zorunda kalan statik kod analizi ile ...


1

IoC kapsayıcısı bağımlılıkları doğru bir şekilde çözmesi gerektiğinden ve bazen birkaç yineleme yapılmasını gerektirdiğinden uygulama başlatma süresini artırabilir.


3
Bir rakam vermek için, bir DI konteyneri saniyede binlerce bağımlılığı çözmelidir. ( codinginstinct.com/2008/05/… ) DI kapları ertelenmiş örneklemeye izin verir. Performans (büyük uygulamalarda bile) bir sorun olmamalıdır. Ya da en azından performans sorunu ele alınmalı ve IoC ve çerçevelerine karşı karar vermek için bir neden olmamalıdır.
Robert
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.