Çerçeve yazarken Bağımlılık Enjeksiyonu / IoC kapsayıcı uygulamaları


18

.Net için çeşitli projelerde çeşitli IoC kapları (Castle.Windsor, Autofac, MEF, vb.) Kullandım. Sıklıkla istismar edildiklerini ve bir dizi kötü uygulamayı teşvik ettiklerini gördüm.

IoC konteyneri kullanımı için, özellikle bir platform / çerçeve sağlarken belirlenmiş uygulamalar var mı? Çerçeve yazarı olarak amacım, kodu olabildiğince basit ve kullanımı kolay hale getirmektir. Ben on ya da sadece iki daha bir nesne oluşturmak için bir kod satırı yazmak istiyorum.

Örneğin, birkaç kod fark ettim ve iyi önerilerim yok kokuyor:

  1. Yapıcılar için çok sayıda parametre (> 5). Hizmet yaratmak karmaşık olma eğilimindedir; bileşenlerin nadiren isteğe bağlı olmasına rağmen (belki testlerde hariç) tüm bağımlılıklar yapıcı yoluyla enjekte edilir.

  2. Özel ve iç sınıfların eksikliği; Bu C # ve Silverlight kullanarak belirli bir sınırlama olabilir, ama nasıl çözüldü ile ilgileniyorum. Tüm sınıflar herkese açıksa, bir çerçeve arayüzünün ne olduğunu söylemek zor; muhtemelen dokunmamam gereken özel bölümlere erişmemi sağlıyor.

  3. Nesne yaşam döngüsünü IoC kapsayıcısına bağlama. Nesneleri oluşturmak için gereken bağımlılıkları manuel olarak oluşturmak genellikle zordur. Nesne yaşam döngüsü genellikle IoC çerçevesi tarafından yönetilir. Sınıfların çoğunun Singleton olarak kaydedildiği projeler gördüm. Açık bir kontrol eksikliği elde edersiniz ve ayrıca iç kısımları yönetmek zorunda kalırsınız (yukarıdaki nokta ile ilgilidir, tüm sınıflar herkese açıktır ve bunları enjekte etmeniz gerekir).

Örneğin, .Net çerçevesinin birçok statik yöntemi vardır. DateTime.UtcNow gibi. Birçok kez bunun bir inşaat parametresi olarak sarıldığını ve enjekte edildiğini gördüm.

Somut uygulama bağlı olarak kodumu test etmek zorlaştırır. Bir bağımlılık enjekte etmek benim kodumun kullanımını zorlaştırır - özellikle sınıfın birçok parametresi varsa.

Hem test edilebilir bir arayüzü hem de kullanımı kolay bir arayüzü nasıl sağlayabilirim? En iyi uygulamalar nelerdir?


1
Hangi kötü uygulamaları teşvik ediyorlar? Özel derslere gelince, iyi bir kapsüllemeniz varsa bunların çoğuna sahip olmanız gerekmez; bir kere, test etmek çok daha zor.
Aaronaught

Hata, 1 ve 2 kötü uygulamalardır. Büyük inşaatçılar ve minimal bir arayüz oluşturmak için kapsülleme kullanmıyor musunuz? Ayrıca, özel ve dahili dedim (test etmek için görünür olan iç kısımları kullanın). Hiçbir zaman beni belirli bir IoC konteyneri kullanmaya zorlayan bir çerçeve kullanmadım.
Dave Hillier

2
Sınıf kurucularınız için belki de birçok parametreye ihtiyaç duyduğunun bir işaretinin kendisinin kod kokusu olması ve DIP'nin bunu daha açık hale getirmesi mümkün mü?
dreza

3
Bir kullanarak belirli IoC kapsayıcı bir çerçeve içinde genel olarak iyi bir uygulama değildir. Kullanılması bağımlılık enjeksiyon olan iyi bir uygulama. Aradaki farkın farkında mısınız?
Aaronaught

1
@Aaronaught (ölümden geri döndü). "Bağımlılık enjeksiyonu iyi bir uygulamadır" kullanmak yanlıştır. Bağımlılık Enjeksiyonu, yalnızca uygun olduğunda kullanılması gereken bir araçtır. Bağımlılık Enjeksiyonunu kullanmak her zaman kötü bir uygulamadır.
Dave Hillier

Yanıtlar:


27

Farkında olduğum tek meşru bağımlılık enjeksiyon anti-paterni Servis Bulucu DI çerçevesi kullanıldığında bir anti-patern olan paternidir.

Burada veya başka yerlerde duyduğum diğer sözde DI anti-paternleri, genel OO / yazılım tasarımı anti-paternlerinin biraz daha spesifik durumlarıdır. Örneğin:

  • Yapıcı aşırı enjeksiyonu, Tek Sorumluluk İlkesinin ihlalidir . Çok fazla yapıcı argümanı çok fazla bağımlılığı gösterir; çok fazla bağımlılık sınıfın çok fazla şey yapmaya çalıştığını gösterir. Genellikle bu hata, alışılmadık derecede uzun veya belirsiz ("yönetici") sınıf adları gibi diğer kod kokularıyla ilişkilidir. Statik analiz araçları aşırı afferent / efferent kuplajını kolayca tespit edebilir.

  • Davranışın aksine, veri enjeksiyonu, poltergeist anti-paternin bir alt tipidir ve bu durumda 'geist kaptır. Bir sınıfın geçerli tarih ve saatin farkında olması gerekiyorsa DateTime, veri olan a enjekte etmezsiniz ; bunun yerine, sistem saati üzerine bir soyutlama enjekte edersiniz ( SystemWrappers projesinde ISystemClockdaha genel bir tane olduğunu düşünmeme rağmen genellikle benimkini çağırırım ). Bu sadece DI için doğru değildir; test edilebilirlik için kesinlikle gereklidir, böylece zamanla değişen işlevleri gerçekten beklemenize gerek kalmadan test edebilirsiniz.

  • Her yaşam döngüsünü Singleton olarak ilan etmek bana göre kargo kült programlamanın mükemmel bir örneğidir ve daha az derecede konuşma dilinde " nesne cesspool " dur . Hatırladığımdan daha fazla tekil istismar gördüm ve çok azı DI'yi içeriyor.

  • Başka bir yaygın hata, IOracleRepositoryyalnızca kapsayıcıya kaydedebilmek için yapılan uygulamaya özgü arabirim türleridir (garip adlarla ). Bu tek başına Bağımlılık Tersine Çevirme İlkesinin ihlalidir (sadece bir arayüz olduğu için gerçekten soyut olduğu anlamına gelmez) ve genellikle Arayüz Ayrışma İlkesini ihlal eden arayüz şişkinliğini de içerir .

  • Genellikle gördüğüm son hata , NerdDinner'da yaptıkları "isteğe bağlı bağımlılık" tır . Başka bir deyişle, bağımlılık enjeksiyonunu kabul eden bir kurucu, ama aynı zamanda "varsayılan" bir uygulama kullanan başka bir kurucu vardır. Bu aynı zamanda DIP'yi ihlal eder ve LSP ihlallerine yol açma eğilimindedir , çünkü geliştiriciler zamanla varsayılan uygulama etrafında varsayımlar yapmaya başlar ve / veya varsayılan kurucuyu kullanarak yeni sürüm örnekleri başlatır.

Eski deyişle FORTRAN'ı herhangi bir dilde yazabilirsiniz . Bağımlılık Enjeksiyon onların bağımlılık yönetimini vidalama gelen geliştiriciler engelleyecek bir gümüş kurşun değil, ama does genel hatalar / anti-desenler bir dizi önlemek:

...ve bunun gibi.

Açıkçası , Unity veya AutoFac gibi belirli bir IoC kap uygulamasına bağlı olacak bir çerçeve tasarlamak istemezsiniz. Bu bir kez daha DIP'yi ihlal ediyor. Ancak kendinizi böyle bir şey yapmayı düşünürken bile bulursanız, o zaman zaten birkaç tasarım hatası yapmış olmalısınız, çünkü Bağımlılık Enjeksiyonu genel amaçlı bir bağımlılık yönetimi tekniğidir ve bir IoC konteyneri kavramına bağlı değildir .

Her şey bir bağımlılık ağacı oluşturabilir; belki bir IoC konteyneri, belki bir sürü alayla yapılan bir birim test, belki de kukla veri sağlayan bir test sürücüsüdür. Çerçeveniz umursamamalı ve gördüğüm çoğu çerçeve umursamıyor, ancak yine de son kullanıcının IoC kapsayıcısına kolayca entegre edilebilmesi için bağımlılık enjeksiyonunu ağır kullanıyorlar.

DI roket bilimi değildir. Dış bağımlılıkları olmayan bir yardımcı program yöntemi veya çerçeve dışında herhangi bir amacı bulunamayan bir yardımcı program sınıfı gibi bunları kullanmak için zorlayıcı bir neden olmadığından newve kaçınmaya çalışın static(birlikte çalışma sarmalayıcıları ve sözlük anahtarları, bu).

IoC çerçevelerindeki sorunların birçoğu, geliştiriciler bunları nasıl kullanacaklarını ilk kez öğrendiklerinde ortaya çıkıyor ve aslında IoC modeline uymak için bağımlılıkları ve soyutlamaları ele alma şeklini değiştirmek yerine, IoC kapsayıcılarını beklentilerini karşılamak için manipüle etmeye çalışıyorlar. genellikle yüksek kuplaj ve düşük kohezyon içeren eski kodlama tarzı. Kötü kod, DI tekniklerini kullansın ya da kullanmasın, kötü koddur.


Bir kaç sorum var. NuGet üzerinde dağıtılan bir kütüphane için, kütüphanenin kendisi tarafından değil, kütüphaneyi kullanan uygulama tarafından yapılan bir IoC sistemine güvenemiyorum. Çoğu durumda, kütüphanenin kullanıcısı iç bağımlılıklarını hiç umursamaz. Dahili bağımlılıkları başlatan varsayılan bir kurucuya ve birim testi ve / veya özelleştirilmiş uygulamalar için daha uzun bir kurucuya sahip olmakla ilgili bir sorun var mı? Ayrıca "yeni" önlemek için söyleyin. Bu StringBuilder, DateTime ve TimeSpan gibi şeyler için geçerli mi?
Etienne Charland
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.