9 Stimmen

Dependency Injection ohne Framework

Ich schreibe gerade ein mittelgroßes Analyseprogramm (5-10kloc) in MATLAB (nicht meine Entscheidung) und versuche, meinen Code mit Hilfe von Dependency Injection besser testbar zu machen. Ich glaube, ich verstehe das grundlegende Modell der Objekt-/Konstruktorinjektion, aber ich bin verwirrt darüber, wie sich der Abhängigkeitsgraph dadurch vergrößern lässt.

Wenn ich z. B. ein Objekt A habe, das ein Objekt B hat, das ein Objekt C hat, und Objekt C hat eine Abhängigkeit, die injiziert werden muss, muss ich es dann durch die gesamte Kette schicken? Da es sich um ein Datenanalyseprogramm handelt und alles auf ein AnalyzeData-Objekt bzw. eine AnalyzeData-Methode zurückgeht, bedeutet dies, dass für dieses Objekt alle Abhängigkeiten des gesamten Programms injiziert werden müssen?

Vielleicht ist die Antwort einfach eine ServiceFactory/ServiceProvider in diesem Fall zu verwenden, aber ich würde gerne wissen, ob es möglich ist, viele Abhängigkeiten bis zu einem großen Objektdiagramm ohne ein Framework zu skalieren.

Auch Korrekturen an meinem Denken/Wortlaut/Grundlagen sind erwünscht - ich habe das meiste davon über Google/HN/SO gelernt.

5voto

eljenso Punkte 16300

Matlab-agnostische Antwort:

Wenn (A braucht B) und (B braucht C), dann erstellen Sie zuerst C, dann erstellen Sie B und übergeben C an B. Dann erstellen Sie A und übergeben (B hat C) an A.

Wenn nun C eine Abhängigkeit benötigt, die injiziert werden soll, nennen Sie sie D, können Sie dies auch nach dieser Ereignisfolge tun, indem Sie Setter-Injection verwenden. Dies wäre der Fall, wenn die Abhängigkeit für C optional ist. Andernfalls ist es wahrscheinlich ein Fehler in Ihrer Programminitialisierung, dass C nicht mit D injiziert wurde. avant wurde es an B weitergegeben.

Wenn Sie Konstruktorinjektion verwenden wollen, um D in C zu injizieren, nachdem Sie bereits (A hat (B hat C)) haben, dann müssen Sie Setterinjektion verwenden, um ein neues (C hat D) an B zu übergeben, aber diese Abfolge von Ereignissen ist normalerweise kein gültiges Szenario für DI.

3voto

Dan Punkte 10793

Haftungsausschluss: OO-Sprache agnostische Antwort

Nein, Sie müssen keine Abhängigkeiten über den gesamten Objektgraphen weitergeben. Der Sinn von DI ist es, dass man keine konkreten Typen instanziieren oder als Parameter übergeben muss. Im Allgemeinen haben Sie eine andere Entität, z. B. einen Assembler, der diese Abhängigkeiten injiziert. Der Assembler kann ad-hock, handgeschrieben oder ein DI-Framework sein.

Zum Beispiel:

  • Die Klasse ClsA hat eine Eigenschaft vom Typ Schnittstelle IB.
  • Klasse ClsB implementiert IB und hat eine Eigenschaft vom Typ Schnittstelle IC.
  • Klasse ClsC implementiert IC.

Ihr Assembler bootet die Anwendung und:

  1. Instanz mit dem Namen oC der Klasse erstellen ClsC
  2. eine Instanz namens oB von ClsB und injizieren sie mit oC
  3. eine Instanz mit dem Namen oA erzeugen und sie mit oB

Alle Ihre Domänenobjekte kennen nur Schnittstellen. Der Assembler kennt alle Objekte, aber sein Zweck ist es nur, einen Objektgraphen zu erstellen und alles in Bewegung zu setzen. Handgeschriebener Assembler ist vollkommen angemessen; einige Leute ziehen es vor, Verdrahtungscode zu schreiben, anstatt Konfigurationsdateien zu verwenden. Ich denke nicht, dass es die Mühe wert ist, Assembler (DI-Framework) zu schreiben, wenn Sie nicht vorhaben, ihn mehr als einmal zu verwenden. Der Punkt ist, dass Ihre Klassen in DI-Manier geschrieben sind.

Werfen Sie einen Blick auf diesen Artikel: http://books.google.com/books?id=vRxAnRb3mb4C&pg=PP1&dq=Danijel+Arsenovski#PPA428,M1

2voto

Duncan Punkte 10010

Entwickeln Sie Ihren eigenen IoC-Container, in dem Sie einfach nach Ihren Abhängigkeiten fragen können, ohne sie injizieren zu müssen, oder verwenden Sie das statische Gateway-Muster, um ein Singleton zu erhalten, mit dem Sie Klassen dynamisch mithilfe einer Factory erstellen können.

Ich fand dieses Video eine wirklich nützliche Einführung in diese Themen - http://www.dnrtv.com/default.aspx?showNum=126

2voto

Mendelt Punkte 35649

Wenn Sie Dependency Injection von Hand durchführen, ist es besser, wenn Sie keine Abhängigkeiten durchreichen. Sie erstellen einfach C mit seiner Abhängigkeit, erstellen B mit C, erstellen A mit B. A braucht nichts über C oder seine Abhängigkeit zu wissen. Es weiß nur über die Schnittstelle von B Bescheid und normalerweise sind Abhängigkeiten nicht Teil der Schnittstelle eines Objekts.

2voto

gnovice Punkte 124264

Wenn ich Ihre Frage richtig verstehe, kann die Antwort davon abhängen, wie Sie die Klassen erstellen, aus denen Sie die Objekte instanziieren. In den neuesten Versionen von MATLAB können Klassen auf zwei Arten definiert werden: als "value"-Klasse oder als "handle"-Klasse (MATLAB-Dokumentation aquí ). Ich zitiere aus der Dokumentation:

  • Wertklasse: "Objekte von Wertklassen sind dauerhaft mit den Variablen verbunden, denen sie zugeordnet sind. Wenn ein Wertobjekt kopiert wird, werden auch die Daten des Objekts kopiert und das neue Objekt ist unabhängig von Änderungen am ursprünglichen Objekt. Instanzen verhalten sich wie Standard MATLAB numeric und struct Klassen."

  • Klasse handhaben: "Objekte von Handle-Klassen verwenden ein Handle, um auf Objekte der Klasse zu verweisen. Ein Handle ist eine Variable, die eine bestimmte Instanz einer Klasse identifiziert. Wenn ein Handle-Objekt kopiert wird, wird das Handle kopiert, aber nicht die Daten, die in den Eigenschaften des Objekts gespeichert sind. Die Kopie bezieht sich auf dieselben Daten wie das Original - wenn Sie einen Eigenschaftswert des Originalobjekts ändern, spiegelt das kopierte Objekt die gleiche Änderung wider."

Der folgende Beispielcode enthält einige Beispiele für die Interaktion mit "verschachtelten" Objekten, wie Sie sie oben beschrieben haben, sowohl für verschachtelte Objekte der Klasse value als auch für verschachtelte Objekte der Klasse handle:

% For value classes:

objC = C(...);  % Make an object of class C, where "..." stands
                %   for any input arguments
objB = B(...,objC);  % Make an object of class B, passing it objC
                     %   and placing objC in field 'objC'
objA = A(...,objB);  % Make an object of class A, passing it objB
                     %   and placing objB in field 'objB'

% If the '.' operator (field access) is defined for the objects:

objA.objB.objC.D = 1;  % Set field 'D' in objC to 1
objA.objB.objC = foo(objA.objB.objC,...);  % Apply a method that
                                           %   modifies objC and
                                           %   returns the new
                                           %   object

% For handle classes:

hC = C(...);  % Get a handle (reference) for a new object of class C
hB = B(...,hC);  % Get a handle for a new object of class B,
                 %   passing it handle hC and placing it in field 'hC'
hA = A(...,hB);  % Get a handle for a new object of class A,
                 %   passing it handle hB and placing it in field 'hB'

% If the '.' operator (field access) is defined for the objects:

hC.D = 1;  % Set field 'D' to 1 for object referenced by hC; Note
           %   that hC and hA.hB.hC both point to same object, and
           %   can thus be used interchangably
foo(hC);  % Apply a method that modifies the object referenced by hC

% If instead using get/set methods for the handle object:

set(hC,'D',1);
set(get(get(hA,'hB'),'hC'),'D',1);  % If variable hC wasn't made, get
                                    %   reference from nested objects
foo(hC);
foo(get(get(hA,'hB'),'hC'));

Wie Sie sehen, können Sie durch die Verwendung einer Handle-Klasse vermeiden, dass Sie Funktionsaufrufe und Feldreferenzen verketten müssen, indem Sie eine Kopie des Handles (im Wesentlichen einen Zeiger) in einer anderen Variablen speichern. Handle-Klassen machen es auch überflüssig, alte Kopien von Objekten mit neuen Kopien zu überschreiben, die von Methoden zurückgegeben werden, die mit diesen Objekten arbeiten.

Ich hoffe, das hilft Ihnen bei Ihrer Frage.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X