Bağımlılık Enjeksiyonu ve Statik Yöntemler


21

Bugün bir dize ve çıkış dizesi kabul bir yöntemle bir sınıfa yaklaşmak hakkında başka bir geliştirici ile ilginç bir tartışma vardı.

Tamamen örnek amaçlı yapılmış aşağıdaki gibi bir şey düşünün

public string GetStringPart(string input)
{ 
   //Some input validation which is removed for clarity

   if(input.Length > 5)
        return input.Substring(0,1);

   if(input.Substring(0,1) == "B")
        return input.Substring(0,3);

   return string.empty;
}

Dize girişine dayalı bir mantığı olan bir işlev, DI kullanılarak bir projeye eklenir ve bir DI Kabı vardır. Bu yeni sınıfı bir arabirim ile ekler ve gerektiğinde enjekte eder misiniz, yoksa statik bir sınıf yapar mısınız? Her birinin artıları ve eksileri nelerdir? Neden herhangi bir yere ihtiyaç duyulduğunda erişmektense bunu yapıcı enjeksiyonuyla kullanılan bir şey yapmak istersiniz (ya da istemezsiniz).


1
@Ewan Soyutlama için kullanılmayan yardımcı yöntemler için. Örnek: Apache FileUtils.
Walfrat

3
@Ewan: yan etkisi olmayan statik yöntemler en iyi yöntemlerdir, çünkü anlaşılması ve test edilmesi kolaydır.
JacquesB

1
ancak onlara bağlı olan şeyleri test etmeyi imkansız hale getiriyorlar
Ewan

3
@Ewan Eh, pek değil. Math.Max ​​() statik olduğu için kötü mü? Statik yönteminizi test ediyorsanız ve çalışıyorsa, sorunsuz bir şekilde diğer yöntemlerinizde kullanabilirsiniz. Statik olan başarısız olursa, testi onu yakalayacaktır.
T. Sar - Monica'yı

1
Eğer 'statik' hiçbir yan etkiyi garanti etmiyorsa, argümanı görebiliyorum. ama öyle değil.
Ewan

Yanıtlar:


25

Bunun enjekte edilmesi için bir neden yoktur. Bu sadece bir işlevdir, bağımlılıkları yoktur, bu yüzden sadece çağırın. Saf gibi görünmesini istiyorsanız statik bile olabilir. Buna karşı birim testler zorlanmadan yazılabilir. Diğer sınıflarda kullanılırsa, birim testleri yine de yazılabilir.

Bağımlılık olmadan işlevleri soyutlamaya gerek yoktur, aşırıya kaçar.

Bu daha karmaşık hale gelirse bir arayüzün bir kurucuya veya yönteme geçirilmesi gerekebilir. Ancak, GetStringPartkonuma dayalı karmaşık bir mantığa sahip olmadıkça, o yoldan aşağıya gitmezdim.


2
Bu doğru cevap! Kötü niyetli kargo kültünün cevabı kabul edildi.
JacquesB

3
işlevin hiçbir bağımlılığı olmadığı önemli değildir. sorun, diğer şeyler işleve bağlı olduğunda ve ona sıkıca bağlı olduğunda
Ewan

2
İşlev 6 ay içinde değişir ve çok saf değilse, ancak zaten birçok yerde kullanılır. Statik olarak genişletilemez ve aynı zamanda sınıf birimi testlerini tüketmekten izole edilebilecek bir şey değildir. Değişimde hafif bir şans olsa bile, onu enjekte etmeye giderdim. Bununla birlikte, karşıt argümanları dinlemeye açıkım, bu yazının amacı bu. Bunun enjekte edilmesinin ve statik elektriğin olumlu yanları nelerdir?
James

1
Genel olarak, bu web sitesinde bağımlılık enjeksiyonunu tartışan kişilerin bağımlılık enjeksiyonuna ihtiyacı yoktur. Dolayısıyla gereksiz karmaşıklığa karşı önyargı.
Frank Hileman

2
@James İşlev daha az saflaşırsa, yanlış bir şey yapıyorsunuzdur ve işlev muhtemelen başlangıçtan itibaren iyi tanımlanmamıştır. Bir karenin alanının hesaplanması aniden bir veritabanı çağrısına ihtiyaç duymamalı veya kullanıcı arayüzü için görsel bir güncelleme dağıtmamalıdır. Bir tür "Substring" yönteminin aniden saf olmadığı bir senaryo hayal edebiliyor musunuz?
T. Sar - Monica'yı

12

İşte nedeni

class DOSClient {
    OrderParser orderParser;
    string orderCode;

    DOSClient(OrderParser orderParser, string ordercode) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
    }
    void DisplayOrderCode() {
        Console.Write( "Prefix: " + orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class GUIClient {
    OrderParser orderParser;
    string orderCode;
    GUI gui;

    GUIClient(OrderParser orderParser, string ordercode, GUI gui) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
        this.gui = gui;
    }

    void DisplayOrderCode() {
        gui.Prefix( orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

 

class OrderParserUS : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 5)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "B")
            return input.Substring(0,3);

        return string.empty;
    }
}

class OrderParserEU : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 6)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "#")
            return input.Substring(0,3);

        return string.empty;
    }
}

Statik bir yöntemle gitmiş olsaydınız GetStringPart, eski davranışı yok etmeden veya koşullu mantıkla kirletmeden davranışını değiştirmenin bir yolu olmazdı . Statiklerin kılık değiştirmiş kötü küreseller olduğu doğrudur, ancak polimorfizmi devre dışı bıraktıkları gerçeği, bunlar hakkında benim ana şikayetim. Statik yöntemler OOP dillerinde birinci sınıf değildir. Yönteme yaşamak için bir nesne, hatta durumu olmayan bir nesne vererek, yöntemi taşınabilir hale getiririz. Davranışı bir değişkenin değeri gibi geçirilebilir.

Burada Avrupa'da konuşlandırıldıktan sonra ABD'de konuşlandırıldığında biraz farklı davranması gereken bir sistem hayal ettim. Daha sonra her iki sistemi de sadece diğerinin ihtiyaç duyduğu kodu içermeye zorlamak istemcilere hangi sıra ayrıştırma nesnesinin enjekte edildiğini kontrol ederek davranışı değiştirebiliriz. Bu, bölge detaylarının yayılmasını kontrol etmemizi sağlar. Ayrıca, mevcut ayrıştırıcılara dokunmadan OrderParserCanada eklemeyi de kolaylaştırır.

Bu sizin için bir şey ifade etmiyorsa, bunun için gerçekten iyi bir argüman yoktur.

BTW, GetStringPartkorkunç bir isim.


* Köşeli parantez kod stili * C # kodu yazmaya çalışan bir Java programcısı olduğunu tahmin ediyorum? Sanırım birini tanımak ister. :)
Neil

Soru bir dile özgü değil, daha çok tasarımla ilgili. Statik yöntemler ile benim sorunum onlar test için kod izolasyonu önlemek. Geliştirici DI hakkında çok fazla güvendiğimi ve bazen uzatma yöntemlerinin / statik yöntemlerin ilgili olduğunu düşünüyor. Muhtemelen nadir durumlarda düşünüyorum ama genel amaç olarak değil. Hissettiğim sürekli tartışma daha fazla tartışmak için iyi bir fikirdi. Ayrıca polimorfizm için yaptığınız davaya da katılıyorum.
James

Test etmek bir sebep ama dahası da var. Bunu testte suçlamaktan çok hoşlanmam çünkü insanları test etmeyi eleştirmeye başlıyor. Basit gerçek şu ki, prosedürel programcılar prosedürel olarak programlamazsanız hoşlanmazlar.
candied_orange

Basitçe söyleyemez static getStringPartEU()misin? Örneğiniz sadece o sınıfta uzmanlaşmış AB muamelesini de gerektiren başka yöntemler varsa ve bunların tek bir birim olarak ele alınması gerektiğinde mantıklıdır.
Robert Harvey

2
Kesinlikle gereksiz karmaşıklık lehine tartışıyorsunuz. Her şeye daha fazla kod eklenebilir. Değişmesi gereken şeylerin değiştirilmesi kolay olmalı, ancak gelecekte neyin değişmesi gerektiğini tahmin etmeye çalışmamalısınız. Statik alanlar global değişkenlerle aynı olabilir, ancak statik yöntemler mümkün olan en iyi yöntem türü olan saf olabilir.
Frank Hileman
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.