Das Prinzip der Abhängigkeitsinversion mit .NET Framework-Klassen

8

Ich versuche, SOLID-Prinzipien zu verstehen, insbesondere Prinzip der Abhängigkeitsinversion .

In dieser SO Antwort wird das sehr gut erklärt.

Ich glaube, ich habe verstanden, dass ich in meiner Klasse keine Instanz einer Klasse erstellen kann. Ist es richtig?

Aber wenn ich einige Inhalte auf Platte speichern muss, kann ich eine Instanz von System.IO.File oder muss ich es injizieren?

Ich verstehe nicht, wo das Limit liegt, wenn ich meine eigenen Klassen nicht instanziieren kann oder wenn ich .NET Framework-Klassen (oder irgendein anderes Framework) nicht instanziieren kann.

AKTUALISIEREN :
Ich denke File ist ein schlechtes Beispiel, weil es als statisch deklariert ist.

Dieser Grundsatz gilt übrigens auch für statische Klassen ?

    
VansFannel 20.07.2017, 11:13
quelle

3 Antworten

3

Das S von SOLID steht für SRP (Single Responsibility Principle). Du wirst es nicht verletzen, indem du System.IO.File direkt in einer Klasse verwendest, wenn du diese Klasse mit einer einzigen Verantwortung behälst.

Es ist eine gute Idee, den Zweck der Verwendung von System.IO.File zu abstrahieren. Nehmen wir an, Sie benötigen es, um ein Protokoll zu generieren. Dann würden Sie wahrscheinlich etwas tun wie:

%Vor%

Vielleicht ist es nicht nur ein Protokoll, es ist etwas wichtiger, als eine Datei zu generieren, damit andere Systeme / Anwendungen (sogar externe) sie lesen und etwas tun.

Wenn Sie versuchen, einen DDD-Ansatz zu verwenden, könnte die Schnittstelle zu Ihrer Domäne gehören und die Implementierung könnte in die Anwendung gehören. Dann registrieren Sie Ihre Schnittstelle als Dienst und injizieren sie.

Die Klasse, die ein IMyLogger benötigt, muss eigentlich nicht wissen, wie das Protokoll erzeugt wird, es muss nur der Job erledigt werden.

Sie können dieselbe Idee anwenden, wenn Sie eine E-Mail innerhalb einer Geschäftslogik in Ihrer Domain senden müssen. Erstellen Sie nicht eine direkte Verbindung zu einem Exchange innerhalb Ihrer Domäne, sondern erstellen Sie eine Schnittstelle INotifier und eine MailNotifier , die es implementiert, um es zu injizieren.

    
Alisson 20.07.2017 11:24
quelle
2

Irgendwo in der Kette der Abhängigkeiten müssen Sie die konkrete Klasse direkt verwenden. Selbst wenn Sie ein DI-Framework wie Ninject verwenden, wird das Framework selbst eine Instanz des konkreten Typs erstellen, sodass es nicht in das Framework eingefügt wird (was natürlich keinen Sinn ergeben würde).

Sie können nur etwas auf eine bestimmte Ebene abstrahieren. Es wird von Projekt zu Projekt variieren - Sie müssen sich fragen, ob Sie eine andere Abstraktionsebene benötigen (sei es für Modularität, Komponententests usw.). Ich denke, das ist sehr wichtig - Sie wollen pragmatisch sein, nicht Schichten für Schichten von Abstraktionen erstellen, nur um es zu wollen.

  

Gilt dieses Prinzip übrigens auch für statische Klassen?

Ja, tut es. Bei statischen Klassen müssen Sie jedoch einen Wrapper einführen, der Aufrufe an die statische Klasse delegiert, da eine statische Klasse keine Schnittstellen implementieren kann.

    
Kapol 20.07.2017 11:31
quelle
1

Es macht keinen Sinn, ein Prinzip nur dafür zu verwenden. Denken Sie pragmatisch.

Wenn Sie eine Methode testen möchten, die fest codierte Dateizugriffe verwendet, greifen Ihre Komponententests auf diese Dateien zu. Dies ist normalerweise nicht erwünscht, da Sie diese Dateien einrichten oder bereinigen müssen. Um dies zu vermeiden, würden Sie einen Dienst hinzufügen, der diese Dateizugriffe umschließt. Auf diese Weise können Sie während der Komponententests den echten Service durch einen falschen ersetzen. Dieser gefälschte Dienst kann fest codierte Testdaten für Lesezugriffe bereitstellen und geschriebene Daten zur späteren Analyse in den Speicher ablegen oder einfach nichts tun. Btw .: NSubstitute kann zur Laufzeit leicht gefälschte Dienste erstellen.

Durch die Injektion von Diensten können Sie die Isolation von Komponententests erreichen. Z.B. Sie können eine gewisse Logik testen, ohne von der korrekten Handhabung von Dateien oder Datenbankzugängen oder der korrekten Funktion anderer Dienste abhängig zu sein. Das Einfügen eines Dienstes ist nur eine Möglichkeit. Sie können stattdessen auch einen Methodenparameter als IEnumerable<string> mit dem Inhalt der Datei angeben. Ereignisse können auch zur Entkopplung verwendet werden. Anstatt in ein Protokoll zu schreiben, können Sie ein Protokollereignis auslösen.

In den meisten DI-Frameworks können Sie die Lebensdauer von Objekten angeben. Eine dieser Optionen ist Singleton , was bedeutet, dass der DI-Container immer dieselbe Instanz eines angeforderten Service zurückgibt. Dies ermöglicht es Ihnen, statische Klassen in einem Dienst zu verpacken, der sich statisch verhält.

    
Olivier Jacot-Descombes 20.07.2017 12:49
quelle