Eine der Möglichkeiten, Dependency Injection korrekt zu implementieren, besteht darin, die Objekterstellung von der Geschäftslogik zu trennen. In der Regel wird hierfür eine Factory zur Objekterstellung verwendet.
Bis zu diesem Punkt habe ich nie ernsthaft darüber nachgedacht, eine Factory zu benutzen, also entschuldige ich mich, wenn diese Frage etwas simpel erscheint:
In all den Beispielen des Factory-Patterns, die ich durchlaufen habe, sehe ich immer sehr einfache Beispiele, die keine Parametrisierung haben. Hier ist zum Beispiel eine Fabrik, die von Misko Hevery ausgezeichnet Überlegungen zum Artikel" new "Operator .
%Vor%Was passiert jedoch, wenn ich möchte, dass jedes Haus, das ich baue, einen Namen hat? Benutze ich noch das Factory-Muster, wenn ich diesen Code wie folgt neu schreibe?
%Vor%Beachten Sie, dass sich mein Factory-Methodenaufruf von diesem geändert hat:
%Vor%Dazu:
%Vor%Übrigens: Ich denke, das Konzept der Trennung von Objekt-Instanziierung von Geschäftslogik ist großartig, ich versuche nur herauszufinden, wie ich es auf meine eigene Situation anwenden kann. Was mich verwirrt ist, dass alle Beispiele, die ich vom Factory-Muster gesehen habe, niemals irgendwelche Parameter in die build () - Funktion übergeben.
Um es klar zu sagen: Ich kenne den Namen des Hauses erst im Moment, bevor ich es instanziieren muss.
Ich habe eine ganze Menge Beispiele gesehen, die einen festen Satz von Argumenten verwenden, wie in Ihrem Namensbeispiel, und ich habe sie auch selbst benutzt und ich kann nichts falsch finden.
Es gibt jedoch einen guten Grund, warum viele Tutorials oder kleine Artikel keine Fabriken anzeigen, die Parameter an die konstruierten Objekte weiterleiten: Es ist praktisch unmöglich, eine beliebige Anzahl von Argumenten weiterzuleiten (selbst für ein vernünftiges Limit wie 6 Argumente). Jeder Parameter, den Sie weiterleiten, muss als const T&
und T&
akzeptiert werden, wenn Sie dies generisch machen wollen.
Für kompliziertere Beispiele benötigen Sie jedoch eine exponentiell wachsende Menge an Überladungen (für jeden Parameter eine const- und eine nonconst-Version) und perfect forwarding ist gar nicht möglich (so werden zB Provisorien als Provisorien weitergeleitet) . Für den nächsten C ++ Standard ist dieses Problem gelöst:
%Vor%Auf diese Weise können Sie
anrufen %Vor%Und es wird zurückkehren
%Vor%Lesen Sie den oben verlinkten Artikel.
Ich kann nicht verstehen, warum es falsch wäre, diesen Parameter zu Ihrer Fabrik hinzuzufügen. Beachten Sie jedoch, dass Sie nicht viele Parameter hinzufügen sollten, die nicht für alle von der Factory erstellten Objekte nützlich sein könnten. Wenn Sie das tun, haben Sie ziemlich viele Vorteile einer Fabrik verloren!
Nicht nur ist akzeptabel, es ist häufig , Parameter an eine Factory-Methode zu übergeben. Sehen Sie sich einige Beispiele an. Normalerweise ist der Parameter ein Typ, der der Fabrik sagt, was zu tun ist, aber es gibt keinen Grund, warum Sie keine anderen Informationen hinzufügen können, die Sie zum Erstellen eines Objekts benötigen. Ich denke, was du machst ist in Ordnung.
Die Idee einer Fabrik ist, dass sie Ihnen eine Instanz einer Klasse / Schnittstelle gibt, also ist nichts falsch daran, Parameter zu übergeben. Wenn dies der Fall wäre, wäre es auch schlecht, Parameter an ein neues () zu übergeben.
Ich stimme Benoit zu. Denken Sie an eine Fabrik, um etwas wie SQL-Verbindungen zu erstellen, in einem Fall wie diesem wäre es notwendig, Informationen über die Verbindung zur Fabrik zu übermitteln. Die Fabrik verwendet diese Informationen, um das richtige Serverprotokoll usw. zu verwenden.
Sicher, warum nicht ...!?
Das Schöne an der Übergabe von Parametern ist, dass Sie die Implementierung des konkreten Objekts ausblenden können. In dem von Ihnen geposteten Code übergeben Sie beispielsweise die Parameter an den Konstruktor. Sie können die Implementierung jedoch so ändern, dass sie über eine Initiailze -Methode übergeben werden. Indem Sie Parameter an die Factory-Methode übergeben, verdecken Sie die Art der Konstruktion und Initialisierung des Objekts vom Aufrufer.
Sieh dir Loki :: Factory an, es gibt eine Implementierung, die Boost sehr ähnlich ist. Einige Beispiel-Code verwende ich regelmäßig in verschiedenen Geschmacksrichtungen:
typedef Loki :: SingletonHolder & lt; Loki :: Fabrik & lt; Komponente, std :: string, Loki :: Typeliste & lt; const DataCollection & amp; Loki :: Typeliste & lt; Spiel *, Loki :: NullType & gt; & gt; & gt; & gt; ComponentFactory;
Das mag auf den ersten Blick etwas komisch erscheinen, aber lassen Sie mich dieses Biest erklären und wie mächtig es wirklich ist. Grundsätzlich erstellen wir einen Singleton, der eine Factory enthält, die meisten Parameter sind für den Singleton, Component ist unser Produkt, std :: string ist unser Erstellungs-ID-Typ, danach folgt eine Typenliste der Parameter, die für die Erstellung von Components benötigt wird (Dies kann auch mit einem Makro für eine weniger ausführliche Syntax definiert werden). Nach dieser Zeile kann man einfach tun:
ComponentFactory :: Instance (). CreateObject ("someStringAssociatedWithConcreteType", anDataCollection, aGamePointer);
Um Objekte zu erstellen, benutzen Sie ComponentFactory :: Instance (). Register () ;. Es gibt ein großes Kapitel über die Details in dem Buch Modern C ++ Design.
Tags und Links c++ dependency-injection factory