Verstehe ich DI / IoC richtig? [geschlossen]

8

Ich versuche derzeit, die Vorteile der Verwendung eines IoC-Containers zu lernen und mich mit DI vertraut zu machen. Ich habe begonnen, StructureMap zu verwenden, da es ziemlich einfach und doch mächtig scheint.

Ich möchte bestätigen, dass mein Verständnis dieser Konzepte korrekt ist. Nehmen wir die folgenden rudimentären Klassen in einer Anwendung an (Details, die der Kürze halber weggelassen werden):

%Vor%

In erster Linie besagt das Dependency Inversion Principle, dass der OrderService ein "High-Level" -Modul ist, das nicht von den Implementierungsdetails irgendeiner niedrigeren Ebene abhängen sollte, sondern nur Referenzen auf diese Klassen haben und dazu in der Lage sein sollte Bitten Sie sie, ihr Ding zu machen, ohne was es tun muss, und der konsumierende Code sollte dafür verantwortlich sein, diese vorkonfigurierten Module zu erstellen und zu übergeben. Ist das richtig? Daher hält DI diese Klassen lose gekoppelt, so dass sie nicht genau wissen müssen, wie eine Methode für diese Abhängigkeit aufgerufen wird, einfach so, dass sie aufgerufen wird und alles tut, was sie tun muss - Es ist dem OrderService egal, ob das Repository XML abfragt oder NHibernate oder EF oder sogar rohe DataSets verwendet. es weiß nur, dass es in das Repository aufrufen kann, dass es eine Order mit einer ID von 42 findet und das Repository weiß, was zu tun ist.

Es ist auch mein Verständnis, dass ein IoC-Container, StructureMap in diesem Fall, einen Vorteil bietet, indem er uns nicht dazu zwingt, sicherzustellen, dass wir alle diese Abhängigkeiten von Hand erstellen und übergeben. Zum Beispiel die Main-Methode eines Trivialen App mit dem obigen Code könnte haben:

%Vor%

was widerlich hässlich ist mit all den Neuigkeiten, um es aufzustellen; selbst wenn ich Variablen erstellt habe, ist es immer noch hässlich. Die Verwendung des IoC-Containers lässt mich all dies vermeiden und im Falle von StructureMap würde es zu:

%Vor%

Was ist viel sauberer, einfacher zu warten, und lässt mich einfach die konkrete Klasse für, sagen wir, ein Mock ausgliedern, wenn ich einen Komponententest schrieb. Kurz gesagt, der Vorteil ist, dass es alles noch mehr entkoppelt, wo ich nicht einmal darauf achten muss (in dem aufrufenden Code, das ist), worauf eine bestimmte Klasse angewiesen ist, ich kann einfach eine mit dem Container erstellen und es tun lassen es ist Sache und stellen Sie sicher, dass der konsumierende Code nur weiß, was er braucht - zum Beispiel in einer echten App, wenn der Controller den Dienst anruft, er nicht über Repositories oder Taschenrechner oder Spezifikationen Bescheid wissen muss, alles was er wissen muss ist zu verwenden der OrderService etwas mit einer Bestellung zu tun.

Ist das richtig? In diesem Sinne gibt es ein paar Dinge, über die ich mir noch nicht sicher bin:

  1. Wenn Sie sich für die Verwendung eines IoC-Containers entscheiden, soll es überall in der Anwendung verwendet werden, nur dort, wo Sie viele umgekehrte Abhängigkeiten haben, oder nur im Consumer? Zum Beispiel im OrderRepository, wenn ich eine konkrete Implementierung verwende und einen Auftrag neu erstelle; Würde diese Klasse auch StructureMap verwenden, um den Auftrag zu erhalten? Dies könnte eine etwas alberne Frage sein, aber alle DI / IoC-Beispiele, die ich gesehen habe, konzentrieren sich nur darauf, sie in dem konsumierenden Client (z. B. einer Webseite) zu verwenden, und berühren sie nie anderswo. Es scheint, als wäre es ein Alles-oder-Nichts-Ansatz: Wenn Sie einen IoC-Container verwenden, wird er überall verwendet. Sie ersetzen im Prinzip jeden Aufruf von new SomeObject(); , in diesem Fall ObjectFactory.GetInstance<ISomeObject>();

  2. Wird es als gut oder schlecht angesehen, wenn jede Klasse (wo immer möglich) von einer Schnittstelle abgeleitet wird, unabhängig davon, ob es notwendig ist, DI / IoC zu verwenden oder so etwas zu verspotten? Ich habe viele Codebeispiele gesehen, in denen jede einzelne Klasse, die keine eingebaute Klasse ist, eine Schnittstelle hinter sich hat, und während ich die Vorteile und mögliche Zukunftssicherheit dieser Vorgehensweise sehen kann, und ich nehme an, dass die folgende TDD oder BDD eine sein könnte Faktor hier als Verwendung dieser Methoden wird Ihnen normalerweise sagen, ob Sie eine Schnittstelle für eine Klasse benötigen, aber ich habe gesehen und mit vielen Menschen gesprochen, die, TDD oder nicht, das Gefühl haben, dass Sie den Typ eines Objekts nie als eine konkrete Klasse definieren sollten; Es sollte immer eine Schnittstelle oder abstrakte Klasse als zugrunde liegenden Typ sein. Das scheint so zu sein, als wäre es ein "Needless Complexity" -Code-Geruch, ganz zu schweigen von einer Verletzung von YAGNI.

Wayne Molina 05.01.2011, 19:12
quelle

2 Antworten

4

Beide Fragen betreffen kontroverse Themen, aber ich werde mich auf meine Seite der Debatten einlassen.

  

Wenn Sie sich für einen IoC-Container entscheiden,   soll es überall in gebraucht werden   die Anwendung, nur wo Sie haben   viele invertierte Abhängigkeiten zu lösen,   oder nur im Verbraucher?

Ihre Top-Level-Anwendung (der Consumer) ist die einzige Komponente, die über Ihr Framework zur Abhängigkeitsinjektion Bescheid wissen sollte. Sie müssen new nicht in Ihrer gesamten Codebasis ersetzen, da jedes Objekt alle abhängigen Instanzen haben muss, damit es seine Aufgabe erfüllen kann (Miško Heverys " Dependency Injection Mythos: Referenz Passing " war, was schließlich für mich nach Hause fuhr).

  

Ist es gut oder schlecht zu haben?   jede Klasse (wo möglich, von   Natürlich) von einer Schnittstelle ableiten   ob es nötig ist oder nicht   DI / IoC oder etwas wie es zu verspotten?

Der Rest dieser Frage zeigt, dass Sie die Antwort bereits wissen: Erstellen Sie nur Schnittstellen, um geeignetere Abstraktionen zu erzeugen (als die konkrete Klasse in Frage) oder um einen anderen Wert zu liefern.

    
Jeff Sternal 05.01.2011, 20:16
quelle
1

Ich arbeite derzeit intensiv mit DI / IoC in C # / WinForm auf VisualStudio2010 / 12. Meine Wahl fällt auf Castle Windsor, aber auch StructureMap ist aber nicht wichtig was IoCC benutzt.

Für eine sehr detaillierte Antwort empfehle ich Ihnen, "Dependency Injection in .NET" von Mark Seemann zu lesen. Das ist ein gutes Buch, auch wenn Sie nicht in .NET entwickeln.

In Bezug auf Ihre Fragen:

  1. Ein DI CONTAINER ist eine Bibliothek, die Sie von wo auch immer verwenden können wie - aber das heißt nicht, dass Sie sollten. Obwohl Sie die Verwendung von verteilen können der Container, so dass es einen großen Prozentsatz Ihrer Klassen durchdringt, sollten Sie Konzentriere dich stattdessen auf einen einzigen Bereich deiner Bewerbung.

    Dieser Ort heißt der ZUSAMMENSETZUNG ROOT und Sie sollten nur einen DI CONTAINER von diesem Ort verwenden. Die COMPOSITION ROOT der Anwendung sollte sich in der Anwendung befinden root, damit es die Anwendung richtig erstellen kann. Sie sollten nicht versuchen, Klassen in irgendeinem der Module zu komponieren, weil das Ansatz begrenzt Ihre Möglichkeiten. Alle Klassen in Anwendungsmodulen sollten CONSTRUCTOR verwenden INJECTION (oder, in seltenen Fällen, eines der anderen Muster wie Property Injection) und belassen es der COMPOSITION ROOT, um das Objektdiagramm der Anwendung zu erstellen. Irgendein DI-BEHÄLTER Anruf sollte auf die COMPOSITION ROOT beschränkt werden.

    Die COMPOSITION ROOT kann auf einige wenige Klassen verteilt werden. Dies ist zu erwarten - wichtig ist, dass alle Klassen in demselben enthalten sind Modul, das ist vorzugsweise die Anwendung root.

  2. Sie sind nicht verpflichtet, überall Schnittstellen zu verwenden. Sie können auch konkrete Klassen verwenden. Sicherlich bieten Schnittstellen ein höheres Abstraktionsniveau, aber Sie müssen überlegen, ob Sie in Ihrem Projekt brauchen. Zum Beispiel ist es ratsam, die Schnittstelle in der Geschäftslogik in Ihrer Anwendung zu verwenden.

abrfra 31.08.2012 09:30
quelle