2

Wir haben derzeit Code, der etwas wie folgt aussieht, mit einer Fabrik in viele Klassen injiziert wird, die dann die Fabrik aufrufen, um eine Instanz von dem, was sie wollen.Generische Registrierung in Windsor mit UsingFactoryMethod

public class Service 
{ 
    public Service(IFactory factory) 
    { 
      _car = factory.GetCar<Entity>(); 
    } 
} 

public class Car : ICar 
{ 
} 

public interface IFactory 
{ 
    ICar<TEntity> GetCar<TEntity>(); 

    IBoat<TEntity> GetBoat<TEntity>(); 
} 

public class Factory : IFactory 
{ 
    ConnectionDetails _connectionDetails;  

    public Factory(ConnectionDetails connectionDetails) 
    { 
     _connectionDetails = connectionDetails; 
    } 

    TEntity GetCar<TEntity>() 
    { 
     var car = new Car<TEntity>(_connectionDetails); 
     car.Initialize(); 
     return car; 
    } 
} 

Ich hatte gehofft, eine Lösung zu schaffen in der Lage sein, die eine Abhängigkeit direkt für die Anforderung auf dem Car<TEntity>, ohne dass durch die Fabrik gehen zuerst erlauben würde.

Unten ist ein Beispiel für die Installation für eine einzige TEntity, aber wie würde ich dies als generische einrichten?

Ich habe versucht, offene Generika zu verwenden, aber ich kann nicht sehen, wie ich den richtigen Rückgabetyp aus .UsingFactoryMethod() bekommen kann.

Ich weiß, ich kann die RequestedType aus der CreationContext, aber ich sehe nicht, wie ich das verwenden, um dieses Problem zu lösen.

public class Installer : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(
        Component.For<ICar<TEntity>>().UsingFactoryMethod(
         kernel => 
         { 
          var factory = kernel.Resolve<IFactory>(); 
          return factory.GetCar<TEntity>(); 
         })); 
    } 
} 

Antwort

1

Persönlich finde ich, dass mit Dependency Injection gemischt Fabriken ein bisschen anti-Muster sein können, da es Implementierung/creation Details irgendwo anders als die Objektgraph Wurzel versteckt. Darüber hinaus wird unklar, wer letztendlich die Verantwortung für die Erstellung und Pflege von Objekten und deren Lebenszyklen trägt.

Ich würde empfehlen, dass Sie den Container dazu veranlassen, die Erstellungsdetails basierend auf allgemeinen Basisschnittstellen/Klassen vollständig zu verarbeiten.

void Main() 
{ 
    var container = new WindsorContainer(); 
    container.Install(new Installer()); 

    var car = container.Resolve<Car>(); 
    car.Dump(); 
} 

public class Service 
{ 
    private ICar<CarEntity> _car; 

    public Service(ICar<CarEntity> car) 
    { 
     _car = car; 
    } 
} 

public class TEntity { } 
public class CarEntity : TEntity { } 
public class BoatEntity : TEntity { } 

public interface ICreatable { } 
public interface ICar<TEntity> : ICreatable { } 

public class Car : ICar<TEntity> 
{ 
    private ConnectionDetails _connectionDetails; 

    public Car(ConnectionDetails connectionDetails) 
    { 
     _connectionDetails = connectionDetails; 
     Initialize(); 
    } 

    public void Initialize() {} 
} 

public class ConnectionDetails { } 

public class Installer : IWindsorInstaller 
{ 
    public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
     container.Register(
      Component.For<ConnectionDetails>() 
        .ImplementedBy<ConnectionDetails>()); 

     container.Register(
      Classes.FromAssemblyInThisApplication() 
       .BasedOn(typeof(ICreatable)) 
       .WithServiceAllInterfaces() 
       .WithServiceSelf() 
       .LifestyleTransient()); 
    } 
} 
+0

Ich hatte nicht wirklich daran gedacht, das Verhalten dieser Klassen zu ändern, aber das macht Sinn. Ich sollte die Fabrik alle zusammen überspringen können. Ich werde es versuchen. – lxalln

+0

Sie werden feststellen, dass das Skalieren beim Hinzufügen neuer Typen wesentlich einfacher ist, da Sie nicht mehr auf die Änderung der Factory angewiesen sind, um die Erstellungsdetails zu verwalten. –

+0

Das funktioniert jetzt gut, ich hatte gerade nicht an eine Umstrukturierung gedacht. Die Fabrik existierte bereits, ich hatte nicht darüber nachgedacht, sie zu veralten. – lxalln

1

können Sie Castle verwenden Typed Factory Facility dies zu erreichen.

Zuerst müssen Sie eine Schnittstelle schaffen, das Schloss umsetzen:

public interface IFactory 
{ 
    ICar<TEntity> CreateCar<TEntity>(ConnectionDetails connectionDetails); 
    IBoat<TEntity> CreateBoat<TEntity>(ConnectionDetails connectionDetails); 
    void Release(object component); // left type as object so it can release either a boat or a car 
} 

Mit dieser Implementierung, solange Ihr Objekt in dem Behälter mit dem geschlossenen generischen Typ als Dienstname Burg automatisch in der Lage registriert sein um das richtige Objekt zu finden.

Dann brauchen Sie nur die Möglichkeit, hinzuzufügen und Ihre Fabrik Schnittstelle registrieren:

kernel.AddFacility<TypedFactoryFacility>(); 
kernel.Register(Component.For<IFactory>().AsFactory()); 

Der Artikel, den ich an der Spitze verknüpfen auch die Namen Semantik der Methoden in der Schnittstelle umfasst wie einige Worte gegeben sind besondere Bedeutung .

+0

Das Problem hier ist, dass die CreateCar und CreateBoat Methoden anderen Code in ihnen haben. Ich habe darüber nachgedacht, zu diesem Punkt zu kommen, konnte es aber nicht ganz erreichen. – lxalln

+0

Je nachdem, welche zusätzlichen Dinge Sie benötigen, können Sie auch eine benutzerdefinierte Komponentenauswahl für die Fabrik hinzufügen. Dieser Artikel behandelt dieses Thema ebenfalls. – Phaeze

+0

Wir haben schon einige Male Selektoren für benutzerdefinierte Komponenten verwendet. Sie können nur auswählen, welcher Typ von Windsor ausgewählt werden soll. – lxalln

Verwandte Themen