2

В настоящее время у нас есть код, который выглядит примерно так, как показано ниже, при этом завод вводится во множество классов, которые затем вызывают фабрику, чтобы получить экземпляр того, что они хотят.Общая регистрация в Виндзоре с использованиемFactoryMethod

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; 
    } 
} 

Я надеялся, чтобы иметь возможность создать решение, которое позволило бы для запроса зависимость непосредственно на Car<TEntity> без необходимости проходить через завод первым.

Ниже приведен пример установки для одного TEntity, но как бы я установил его как общий?

Я пробовал использовать открытые дженерики, но я не вижу, как я могу получить правильный тип возврата из .UsingFactoryMethod().

Я знаю, что могу получить RequestedType из CreationContext, но я не вижу, как я могу использовать это для решения этой проблемы.

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>(); 
         })); 
    } 
} 

ответ

1

Лично я считаю, что заводы, смешанные с инъекцией зависимостей может быть немного анти-паттерна, так как она скрывает детали реализации/создания где-то, кроме корневого объекта графа. Кроме того, при смешивании двух становится неясным, кто в конечном итоге несет ответственность за создание и поддержание объектов и их жизненных циклов.

Я бы рекомендовал вам перейти на разрешение контейнеру полностью обрабатывать детали создания на основе общих базовых интерфейсов/классов.

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

Я действительно не думал об изменении поведения этих классов, но это имеет смысл. Я должен быть в состоянии пропустить фабрику все вместе. Я отдам его. – lxalln

+0

Вы обнаружите, что это значительно облегчает масштабирование при добавлении новых типов, так как вы больше не зависите от изменения фабрики, чтобы обрабатывать детали создания. –

+0

Это хорошо работает сейчас, я просто не думал о реструктуризации настолько глубоко. Фабрика уже существовала, я не считал ее устаревшей. – lxalln

1

Для этого вы можете использовать Typed Factory Facility Castle.

Прежде всего, необходимо создать интерфейс, который замок будет осуществлять:

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 
} 

С этой реализации, пока ваш объект зарегистрирован в контейнере с закрытой родового типа, как его название службы замок будет автоматически иметь для поиска правильного объекта.

Тогда вам просто нужно добавить объект и зарегистрировать свой фабричный интерфейс:

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

В статье я связан в верхней части также охватывает именовании семантику методов в интерфейсе, как некоторые слова придается особое значение ,

+0

Проблема в том, что методы CreateCar и CreateBoat содержат в них другой код. Я действительно пытался попытаться дойти до этого момента, но не мог этого достичь. – lxalln

+0

В зависимости от того, какие дополнительные вещи вам нужны, вы также можете добавить настраиваемый селектор компонентов для использования на заводе. Эта статья также охватывает эту тему. – Phaeze

+0

Мы уже несколько раз использовали пользовательские селектора компонентов, они просто позволяют выбрать, какой тип должен быть выбран Windsor? – lxalln

 Смежные вопросы

  • Нет связанных вопросов^_^