23

Ich bin endlich meine Füße nass mit Dependency Injection (überfällig); Ich begann mit Unity zu spielen und stieß auf ein Problem mit dem Strategie-Muster. Ich kann den Container verwenden, um spezifische Implementierungen einer Strategie basierend auf einem Namen auf mich zurückzubringen, aber was ich nicht sehe, ist, wie ich die richtige Strategie im Kontext bekommen soll.
Lassen Sie uns an einem einfachen Beispiel veranschaulichen: der Kontext ist ein Auto, das eine IEngine (die Strategie) mit 2 Implementierungen, FastEngine und SlowEngine hat. Der Code würde in diese Richtung suchen:Strategie Muster und Abhängigkeit Injektion mit Unity

public interface IEngine 
{ 
    double MaxSpeed 
    { 
     get; 
    } 
} 

internal class FastEngine:IEngine 
{ 
    public double MaxSpeed 
    { 
     get 
     { 
      return 100d; 
     } 
    } 
} 

internal class SlowEngine:IEngine 
{ 
    public double MaxSpeed 
    { 
     get 
     { 
      return 10d; 
     } 
    } 
} 

public class Car 
{ 
    private IEngine engine; 
    public double MaximumSpeed 
    { 
     get 
     { 
      return this.engine.MaxSpeed; 
     } 
    } 

    public Car(IEngine engine) 
    { 
     this.engine = engine; 
    } 
} 

Mein Problem das ist folgende: Wie soll ich mich über ein schnelles Auto oder ein langsames Auto instanziieren? Ich kann den Container nutzen, um mich bei jeder Implementierung zur Verfügung zu stellen, und ich kann eine „default“ Implementierung gesetzt zu verwenden:

IUnityContainer container = new UnityContainer(); 
container.RegisterType<IEngine, FastEngine>(); 
container.RegisterType<IEngine, FastEngine>("Fast"); 
container.RegisterType<IEngine, SlowEngine>("Slow"); 
var car = container.Resolve<Car>(); 
Assert.AreEqual(100, car.MaximumSpeed); 

aber was würde Ich mag in der Lage sein, ein Auto mit einer spezifischen Implementierung der beantragen Strategie - so etwas wie

var car = container.Resolve<Car>(??? use "Fast" or "Slow ???); 

Kann ich den Container verwenden, um das zu tun? Oder sollte ich eine Fabrik schreiben, die den Container benutzt? Jede Anleitung wäre willkommen - ich bin mir nicht sicher, ob ich darüber richtig nachdenke!

Antwort

26

Ein übliches Muster in DI ist das zur Laufzeit es wird nur eine einzige Implementierung einer gegebenen Abstraktion geben. Das macht das Leben viel einfacher, da Sie sich nicht mit der Mehrdeutigkeit beschäftigen müssen, die Sie beschreiben.

Manchmal müssen Sie jedoch eine Implementierung basierend auf dem Kontext variieren, z. B. das von Ihnen angegebene Beispiel. Viele DI-Container bieten Möglichkeiten, einen qualifizierenden Parameter anzugeben, aber das bedeutet, dass Sie Ihren Code eng an einen bestimmten DI-Container koppeln.

Eine viel bessere Lösung wäre die Einführung einer Abstract Factory, die bieten kann, was Sie brauchen. So etwas wie

public interface ICarFactory 
{ 
    Car Create(IEngine engine); 
} 

Wenn Sie mehr Strategien injizieren, vielleicht die Builder Entwurfsmuster könnte noch besser passen.

In jedem Fall ist der Punkt, dass statt eine Vielzahl von verschiedenen Autos in den Container registrieren, Sie stattdessen eine einzige ICarFactory-Implementierung registrieren würden.

In Ihrem Client-Code würden Sie die injizierte ICarFactory verwenden, um eine Car-Instanz basierend auf einer bestimmten IEngine zu erstellen.

var car = factory.Create(engine); 
+0

Vielen Dank, aufschlussreiche Antwort. Ich benutze das Strategie-Muster, mit mehreren Strategien, die zur Laufzeit ausgetauscht werden. Standardmäßig würde ich tun, was Sie beschreiben (Factory oder Builder), aber ich sah Strategie Muster und DI sehr verbunden, und obwohl dies helfen könnte. Von dem, was Sie sagen, scheint ein Container nur marginal hilfreich zu sein. – Mathias

+0

Ich denke immer noch Container sind äußerst hilfreich. In diesen Fällen würden sie einfach die Fabrik anstelle der Strategie injizieren, aber ich denke, dass Sie immer noch die Fabrik mit dem Container implementieren könnten ... –

+4

Oh ich denke ich sehe was du meinst; anstatt das richtige Auto zurückzugeben, die richtige Fabrik basierend auf dem Motor zurückgeben. In jedem Fall war Ihr Kommentar zu: Containern, die zur Bereitstellung einer einzelnen Implementierung für eine Abstraktion verwendet wurden, sehr hilfreich. es stimmt mit den Beispielen überein, die ich gesehen habe, die konfigurationsorientiert sind. In diesem Frame können Sie ein Strategie-Pattern erstellen, für eine bestimmte Implementierung wird jedoch nur eine Implementierung konfiguriert. – Mathias

Verwandte Themen