Abhängigkeitsinjektion im Vergleich zu statischen Methoden

21

Ich hatte heute eine interessante Diskussion mit einem anderen Entwickler darüber, wie man sich einer Klasse mit einer Methode nähert, die einen String akzeptiert und einen String ausgibt.

Stellen Sie sich etwas wie das Folgende vor, das zum Zweck des Beispiels vollständig erfunden ist

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

Eine Funktion, deren Logik auf der Eingabe eines Strings basiert, wird mit DI zu einem Projekt hinzugefügt und verfügt über einen DI-Container. Würden Sie diese neue Klasse mit einer Schnittstelle hinzufügen und bei Bedarf einfügen, oder würden Sie sie zu einer statischen Klasse machen? Was sind die Vor- und Nachteile von jedem? Warum sollten Sie (oder nicht) möchten, dass dieses Element mit der Konstruktorinjektion verwendet wird, anstatt nur bei Bedarf an einer beliebigen Stelle darauf zuzugreifen?

James
quelle
1
@Ewan Für Hilfsmethoden, für die keine Abstraktion erforderlich ist. Beispiel: Apache FileUtils.
Walfrat
3
@Ewan: Statische Methoden ohne Nebenwirkungen sind die besten Methoden, da sie einfach zu verstehen und zu testen sind.
JacquesB
1
Aber sie machen es unmöglich, Dinge zu testen, die von ihnen abhängen
Ewan
3
@Ewan Eh, nicht wirklich. Ist Math.Max ​​() schlecht, weil es statisch ist? Wenn Sie Ihre statische Methode testen und sie funktioniert, können Sie sie problemlos auf Ihre anderen Methoden anwenden. Wenn die statische ausfällt, wird sie durch den Test abgefangen.
T. Sar - Wiedereinsetzung von Monica
1
Wenn "statisch" keine Nebenwirkungen garantiert, kann ich das Argument möglicherweise sehen. aber das tut es nicht.
Ewan

Antworten:

25

Es gibt keinen Grund, warum dies injiziert werden muss. Dies ist nur eine Funktion, sie hat keine Abhängigkeiten. Rufen Sie sie einfach auf. Es kann sogar statisch sein, wenn Sie möchten, da es rein aussieht. Dagegen kann man problemlos Unit-Tests schreiben. Wenn es in anderen Klassen verwendet wird, können noch Komponententests geschrieben werden.

Es ist nicht nötig, Funktionen ohne Abhängigkeiten zu abstrahieren, es ist übertrieben.

Wenn dies komplexer wird, ist möglicherweise die Übergabe einer Schnittstelle an einen Konstruktor oder eine Methode gerechtfertigt. Aber ich würde diesen Weg nicht gehen, wenn ich nicht eine komplexe GetStringPartLogik basierend auf dem Ort usw. hätte.

Jon Raynor
quelle
2
Das ist die richtige Antwort! Schade, die Cargo-Kult-Antwort wurde angenommen.
JacquesB
3
dass die Funktion keine Abhängigkeiten hat, ist nicht der Punkt. Das Problem ist, wenn andere Dinge von der Funktion abhängen und eng damit verbunden sind
Ewan
2
Was ist, wenn sich die Funktion in 6 Monaten ändert und nicht mehr so ​​rein ist, aber bereits an vielen Orten verwendet wird? Es ist nicht erweiterbar als statisch und es ist auch nicht etwas, das von aufwändigen Klassen-Unit-Tests isoliert werden kann. Wenn es überhaupt eine kleine Chance gibt, würde ich es mir spritzen lassen. Trotzdem bin ich offen für Gegenargumente, darum geht es in diesem Beitrag. Was sind die Nachteile dieser Injektion und die positiven Eigenschaften einer statischen Aufladung?
James
1
Im Allgemeinen benötigen Personen, die auf dieser Website über Abhängigkeitsinjektion diskutieren, keine Abhängigkeitsinjektion. Daher die Tendenz zu unnötiger Komplexität.
Frank Hileman
2
@James Wenn die Funktion weniger rein wird, machen Sie etwas falsch und die Funktion war wahrscheinlich von Anfang an nicht gut definiert. Das Berechnen der Fläche eines Quadrats sollte nicht plötzlich einen Datenbankaufruf oder ein visuelles Update für die Benutzeroberfläche erfordern. Können Sie sich ein Szenario vorstellen, in dem eine Art "Substring" -Methode plötzlich unrein wird?
T. Sar - Wiedereinsetzung von Monica
12

Hier ist der Grund

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

Wenn Sie sich für eine statische Methode entschieden hätten, gäbe es keine Möglichkeit, das Verhalten von zu ändern, GetStringPartohne entweder das alte Verhalten zu zerstören oder es mit bedingter Logik zu verschmutzen. Es ist wahr, dass Statik böse Globals in Verkleidung sind, aber die Tatsache, dass sie den Polymorphismus deaktivieren, ist meine Hauptbeschwerde über sie. Statische Methoden sind in OOP-Sprachen nicht erstklassig. Indem wir der Methode ein Objekt zum Leben geben, auch wenn es keinen Zustand gibt, machen wir die Methode portierbar. Sein Verhalten kann wie der Wert einer Variablen weitergegeben werden.

Hier habe ich mir ein System vorgestellt, das sich beim Einsatz in Europa etwas anders verhalten muss als beim Einsatz in den USA. Statt zu erzwingen, dass eines der beiden Systeme Code enthält, der nur von dem anderen benötigt wird, können wir das Verhalten ändern, indem wir steuern, welches Ordnungsanalyseobjekt in die Clients injiziert wird. Dies ermöglicht es uns, die Streuung der Regionsdetails einzudämmen. Es macht es auch einfach, OrderParserCanada hinzuzufügen, ohne vorhandene Parser anfassen zu müssen.

Wenn Ihnen das nichts bedeutet, gibt es dafür wirklich kein gutes Argument.

Übrigens GetStringPartist ein schrecklicher Name.

kandierte_orange
quelle
* Du bist ein Java-Programmierer, der versucht, C # -Code zu schreiben? Nimmt man, um einen zu kennen, nehme ich an. :)
Neil
Die Frage ist nicht spezifisch für eine Sprache, sondern eher für das Design. Mein Problem mit den statischen Methoden ist, dass sie die Isolation von Code zum Testen verhindern. Der Entwickler, mit dem ich gesprochen habe, glaubt, ich verlasse mich zu stark auf DI, und manchmal sind Erweiterungsmethoden / statische Methoden relevant. Ich denke möglicherweise in seltenen Fällen aber nicht als Allzweck. Die laufende Diskussion, die ich für gut hielt, sollte weiter diskutiert werden. Ich stimme auch Ihrem Fall für Polymorphismus zu.
James
Testen ist ein Grund, aber es gibt noch mehr. Ich mag es nicht, wenn man zu viel testet, weil es die Leute nur dazu bringt, das Testen zu kritisieren. Die einfache Tatsache ist, dass prozedurale Programmierer es nicht mögen, wenn Sie nicht prozedural programmieren.
candied_orange
Könntest du nicht einfach sagen static getStringPartEU()? Ihr Beispiel ist nur sinnvoll, wenn es in dieser Klasse andere Methoden gibt, die ebenfalls eine spezielle EU-Behandlung erfordern und als eine Einheit behandelt werden müssen.
Robert Harvey
2
Sie plädieren auf jeden Fall für unnötige Komplexität. Alles kann mehr und mehr Code enthalten. Dinge, die sich ändern müssen, sollten leicht zu ändern sein, aber Sie sollten nicht versuchen, vorherzusagen, was sich in Zukunft ändern muss. Statische Felder können mit globalen Variablen identisch sein, statische Methoden können jedoch reine Methoden sein, die bestmögliche Methode.
Frank Hileman