Bağımlılık enjeksiyonu kullanılırken bir sınıfta kaç enjeksiyon kabul edilebilir


9

C # bağımlılık enjeksiyon için Unity kullanıyorum, ancak soru bağımlılık enjeksiyon kullanan herhangi bir dil ve çerçeve için geçerli olmalıdır.

SOLID prensibini takip etmeye çalışıyorum ve bu yüzden çok sayıda soyutlama aldım. Ama şimdi bir sınıfın kaç enjeksiyon enjekte etmesi için en iyi uygulama olup olmadığını merak ediyorum?

Örneğin, 9 enjeksiyonlu bir havuzum var. Bunun başka bir geliştirici için okunması zor olacak mı?

Enjeksiyonların aşağıdaki sorumlulukları vardır:

  • IDbContextFactory - veritabanı için bağlam oluşturma.
  • IMapper - Varlıklardan etki alanı modellerine eşleme.
  • IClock - Özetleri DateTime.Şimdi birim testlere yardımcı olun.
  • IPerformanceFactory - belirli yöntemler için yürütme süresini ölçer.
  • ILog - Günlüğe kaydetme için Log4net.
  • ICollectionWrapperFactory - Koleksiyonlar oluşturur (IEnumerable'ı genişletir).
  • IQueryFilterFactory - db'yi sorgulayacak girdiye dayalı sorgular oluşturur.
  • IIdentityHelper - Giriş yapan kullanıcıyı alır.
  • IFaultFactory - Farklı FaultExceptions oluşturun (WCF kullanıyorum).

Sorumlulukları nasıl devrettiğimle gerçekten hayal kırıklığına uğramadım, ancak okunabilirlik için endişelenmeye başlıyorum.

Sorularım:

Bir sınıfta kaç enjeksiyon yapılması gerektiğine dair bir sınır var mı? Ve eğer öyleyse, nasıl önlenir?

Birçok enjeksiyon okunabilirliği sınırlıyor mu yoksa gerçekten geliştiriyor mu?


2
Kaliteyi rakamlarla ölçmek, genellikle ayda yazdığınız kod satırları tarafından ödenmesi kadar kötüdür. Ancak, mükemmel bir fikir olan bağımlılıkların gerçek örneğini eklediniz. Siz olsaydım, sayma ve katı sınır kavramını ortadan kaldırmak ve kendi başına kalite yerine odaklanmak için sorunuzu yeniden düzenlerdim. Yeniden formüle ederken, sorunuzu çok belirgin hale getirmemeye dikkat edin.
Arseni Mourzenko

3
Kaç kurucu argümanı kabul edilebilir? IoC bunu değiştirmez .
telastin

İnsanlar neden her zaman mutlak sınırlar ister?
Marjan Venema

1
@Telastyn: şart değil. IoC'nin değiştiği şey, statik sınıflara / tektonlara / global değişkenlere güvenmek yerine, tüm bağımlılıkların daha merkezi ve daha “görünür” olmasıdır.
Arseni Mourzenko

@ BremenanVenema: çünkü hayatı daha kolay hale getiriyor. Yöntem başına maksimum LOC veya bir sınıftaki maksimum yöntem sayısını veya bir yöntemdeki maksimum değişken sayısını tam olarak biliyorsanız ve bu önemli olan tek şey, kodu iyi veya kötü olarak nitelemek kolaylaşır. kötü kodu "düzeltmek". Bu, gerçek hayatın bundan daha karmaşık olduğu ve birçok metrik çoğunlukla önemsiz olduğu için talihsiz bir durumdur.
Arseni Mourzenko

Yanıtlar:


11

Çok fazla bağımlılık, sınıfın kendisinin çok fazla şey yaptığını gösterebilir. Çok fazla iş yapıp yapmadığını belirlemek için:

  • Sınıfın kendisine bakın. Onu iki, üç, dörde bölmek mantıklı olur mu? Bir bütün olarak mantıklı mı?

  • Bağımlılık türlerine bakın. Hangileri alan adına özgü, hangileri “global”? Örneğin ILog, aynı düzeyde düşünmeyeceğim IQueryFilterFactory: birincisi, günlüğe kaydetmeyi kullanıyor olsalar bile, çoğu iş sınıfında kullanılabilir. Öte yandan, çok sayıda alana özgü bağımlılık bulursanız, bu sınıfın çok fazla şey yaptığını gösterebilir.

  • Değerlerle değiştirilebilecek bağımlılıklara bakın.

    IClock - Özetleri DateTime.Şimdi birim testlere yardımcı olun.

    Bu DateTime.Now, şimdiki zamanı bilmeyi gerektiren yöntemlere doğrudan geçirilerek kolayca değiştirilebilir .

Gerçek bağımlılıklara bakarak, kötü şeylerin olacağını gösteren hiçbir şey görmüyorum:

  • IDbContextFactory - veritabanı için bağlam oluşturma.

    Tamam, muhtemelen sınıfların veri erişim katmanıyla etkileşime girdiği bir iş katmanının içindeyiz. İyi görünüyor.

  • IMapper - Varlıklardan etki alanı modellerine eşleme.

    Genel resim olmadan bir şey söylemek zor. Mimarinin yanlış olması ve eşlemenin doğrudan veri erişim katmanı tarafından yapılması gerekebilir veya mimarinin mükemmel şekilde olması olabilir. Her durumda, bu bağımlılığın burada olması mantıklıdır.

    Başka bir seçenek, sınıfı ikiye bölmek olacaktır: biri haritalama ile, diğeri gerçek iş mantığı ile ilgilidir. Bu, BL'yi DAL'den daha da ayıracak fiili bir katman yaratacaktır. Eşlemeler karmaşıksa, iyi bir fikir olabilir. Bununla birlikte, çoğu durumda, sadece işe yaramaz karmaşıklık katacaktır.

  • IClock - Özetleri DateTime.Şimdi birim testlere yardımcı olun.

    Sadece şimdiki zamanı elde etmek için ayrı bir arayüze (ve sınıfa) sahip olmak çok yararlı değildir. Ben sadece DateTime.Nowşimdiki zaman gerektiren yöntemlere geçmek istiyorum .

    Zaman dilimleri veya tarih aralıkları gibi başka bilgiler varsa, ayrı bir sınıf anlamlı olabilir.

  • IPerformanceFactory - belirli yöntemler için yürütme süresini ölçer.

    Bir sonraki noktaya bakın.

  • ILog - Günlüğe kaydetme için Log4net.

    Bu tür transcendant işlevler çerçeveye ait olmalı ve gerçek kütüphaneler çalışma zamanında değiştirilebilir ve yapılandırılabilir olmalıdır (örneğin, .NET'teki app.config üzerinden).

    Ne yazık ki, bu (henüz) bir kütüphane seçmenize ve ona bağlı kalmanıza veya gerektiğinde kütüphaneleri değiştirebilmeniz için bir soyutlama katmanı oluşturmanıza izin veren durum değildir. Niyetiniz özellikle kütüphane seçiminden bağımsız olmaksa, bunu seçin. Kütüphaneyi yıllarca kullanmaya devam edeceğinizden eminseniz, soyutlama eklemeyin.

    Kütüphane kullanmak için çok karmaşıksa, bir cephe deseni mantıklıdır.

  • ICollectionWrapperFactory - Koleksiyonlar oluşturur (IEnumerable'ı genişletir).

    Bunun etki alanı mantığı tarafından kullanılan çok spesifik veri yapıları oluşturduğunu varsayacağım. Bir yardımcı program sınıfına benziyor. Bunun yerine, ilgili kurucularla veri yapısı başına bir sınıf kullanın. Başlatma mantığı bir kurucuya sığacak şekilde biraz karmaşıksa, statik fabrika yöntemlerini kullanın. Mantık daha da karmaşıksa, fabrika veya bir oluşturucu deseni kullanın.

  • IQueryFilterFactory - db'yi sorgulayacak girdiye dayalı sorgular oluşturur.

    Neden veri erişim katmanında değil? Adında neden a var Filter?

  • IIdentityHelper - Giriş yapan kullanıcıyı alır.

    Neden bir Helpersonek olduğundan emin değilim . Her durumda, diğer sonekler de özellikle açık olmaz ( IIdentityManager?)

    Her neyse, bu bağımlılığın burada olması çok mantıklı.

  • IFaultFactory - Farklı FaultExceptions oluşturun (WCF kullanıyorum).

    Bu kadar karmaşık bir mantık fabrika paterni kullanmayı gerektiriyor mu? Bunun için Bağımlılık Enjeksiyonu neden kullanılır? Üretim kodu ve testler arasında istisnaların oluşturulmasını değiştirir misiniz? Neden?

    Bunu basitçe yeniden düzenlemeye çalışırdım throw new FaultException(...). Bazı genel bilgilerin istemciye yayılmadan önce tüm istisnalara eklenmesi gerekiyorsa, WCF muhtemelen işlenmeyen bir istisna yakaladığınız ve değiştirip istemciye yeniden gönderebileceğiniz bir mekanizmaya sahiptir.

Bir sınıfta kaç enjeksiyon yapılması gerektiğine dair bir sınır var mı? Ve eğer öyleyse, nasıl önlenir?

Kaliteyi rakamlarla ölçmek, genellikle ayda yazdığınız kod satırları tarafından ödenmesi kadar kötüdür. İyi tasarlanmış bir sınıfta çok sayıda bağımlılığınız olabilir, çünkü birkaç bağımlılık kullanarak boktan bir sınıfa sahip olabilirsiniz.

Birçok enjeksiyon okunabilirliği sınırlıyor mu yoksa gerçekten geliştiriyor mu?

Birçok bağımlılık mantığı takip etmeyi daha zor hale getirir. Eğer mantığı takip etmek zorsa, sınıf muhtemelen çok fazla şey yapıyor ve bölünmesi gerekiyor.


Yorumlarınız ve zamanınız için teşekkür ederiz. Çoğunlukla bunun yerine WCF-mantığına taşınacak FaultFactory hakkında. Bir uygulama TDD-in yaparken hayat kurtarıcı olduğundan IClock'u tutacağım. Belirli bir değerin belirli bir zamanda ayarlandığından emin olmak istediğinizde birkaç kez vardır. Sonra DateTime.Şimdi alay edilebilir olmadığından her zaman yeterli olmayacaktır.
smoksnes

7

Bu, DI'nin sınıfınızın muhtemelen tek bir sınıf olmak için çok büyük hale geldiğini söyleyen klasik bir örnektir. Bu genellikle "vay, DI benim inşaatçılar jüpiter daha büyük yapar, bu teknik korkunç" olarak yorumlanır, ama GERÇEKTEN size söylediği şey "sınıf bir tekne yük bağımlılıkları vardır". Bunu bilerek,

  • Bunun yerine yeni bağımlılıklara başlayarak sorunu halının altına süpürün
  • Tasarımımızı yeniden düşünün. Belki bazı bağımlılıklar her zaman bir araya gelir ve diğer soyutlamaların arkasına gizlenmelidir. Belki sınıfınız 2'ye bölünmelidir. Belki de her biri bağımlılıkların küçük bir alt kümesini gerektiren birkaç sınıftan oluşmalıdır.

Bağımlılıkları yönetmenin sayısız yolu vardır ve kodunuzu ve uygulamanızı bilmeden durumunuzda neyin en iyi olduğunu söylemek imkansızdır.

Son sorularınızı cevaplamak için:

  • Bir sınıfın kaç bağımlılığa sahip olması gerektiğine dair bir üst sınır var mı?

Evet, üst limit "çok fazla". "Çok fazla" kaç tane? "Çok fazla", sınıfın bütünlüğünün "çok düşük" hale gelmesidir. Her şey bağlıdır. Normalde bir sınıfa tepkiniz "vay, bu şeyin çok fazla bağımlılığı var" ise, bu çok fazladır.

  • Enjekte edilen bağımlılıklar okunabilirliği artırır veya incitir mi?

Bence bu soru yanıltıcı. Cevap evet ya da hayır olabilir. Ama en ilginç kısmı bu değil. Bağımlılıkları enjekte etmenin amacı, onları GÖRÜNÜR yapmaktır. Yalan söylemeyen bir api yapmakla ilgilidir. Küresel devleti önlemekle ilgili. Bu, kodu test edilebilir yapmakla ilgilidir. Kuplajı azaltmakla ilgilidir.

Makul tasarlanmış ve adlandırılmış yöntemlere sahip iyi tasarlanmış sınıflar, kötü tasarlanmış olanlardan daha okunabilir. DI gerçekten okunabilirliği gerçekten iyileştirmez veya incitmez, sadece tasarım seçimlerinizi öne çıkarır ve eğer kötüyse gözlerinizi sokar. Bu, DI'nin kodunuzu daha az okunabilir yaptığı anlamına gelmez, sadece kodunuzun zaten bir karmaşa olduğunu gösterdi, sadece gizlemiştiniz.


1
İyi geri bildirim. Teşekkür ederim. Evet, üst limit "çok fazla". - Harika ve çok doğru.
smoksnes

3

Her yerde bulunan "Kod Tamamlandı" nın yazarı Steve McConnel'e göre, genel kural 7'den fazla, sürdürülebilirliği zedeleyen bir kod kokusudur. Şahsen sayının çoğu durumda daha düşük olduğunu düşünüyorum, ancak düzgün bir şekilde DI yapmak Kompozisyon Köküne çok yakın olduğunuzda enjekte etmek için birçok bağımlılığa neden olacaktır. Bu normal ve beklenen bir durumdur. IoC kaplarının faydalı bir şey olmasının nedenlerinden biri ve bir projeye ekledikleri karmaşıklığa değer.

Dolayısıyla, programınızın giriş noktasına çok yakınsanız, bu normal ve kabul edilebilirdir. Programın mantığının derinliklerinde iseniz, muhtemelen ele alınması gereken bir koku.

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.