IoC избегать ввода контейнера

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

public class CreateUserCommand : IDomainCommand{
   /// implementation
}

Каждая команда имеет 1 или более обработчиков со следующей реализацией

public class CreateUserHandler : IDomainCommandHandler<CreateUserCommand>
{
   public void Handle(CreateUserCommand command)
   {
      /// implementation
   }
}

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

public class CommandDispatcher : ICommandDispatcher
{
   private IWindsorContainer container;

   public CommandDispatcher(IWindsorContainer container)
   {
      this.container = container;
   }

   public void Dispatch<T>(T command)
   {
      var commandHandler = container.Resolve<ICommandHandler<T>>();
    commandHandler.Handle(command);

   }
}

Что мне не нравится, так это осведомленность диспетчера о контейнере IoC, но точно так же я не знаю, как я могу разрешить обработчики только тогда, когда они мне нужны. Оболочка Я внедряю фабрику обработчиков в Dispatcher и использую ее для разрешения моих обработчиков во время выполнения?


person Raffaeu    schedule 15.09.2014    source источник
comment
Есть еще один способ сделать это правильно. Вы должны использовать TypedFactory. нигде в вашем приложении не должно быть ссылок на DI-контейнер, а все инструменты и шаблоны, необходимые для этого, описаны в документации.   -  person Ognyan Dimitrov    schedule 15.09.2014


Ответы (2)


Я бы использовал типизированную фабрику создайте фабрику, чтобы заменить использование контейнера. Концептуально идея та же, но она устраняет зависимость от контейнера.

Завод (без реализации, об этом позаботится объект):

public interface ICommandHandlerFactory
{
    ICommandHandler<T> Create<T>();
}

Регистрация:

// requires Castle.Facilities.TypedFactory namespace
windsorContainer.AddFacility<TypedFactoryFacility>();

// AsFactory() is an extension method in the same namespace
windsorContainer.Register(Component.For<ICommandHandlerFactory>().AsFactory());

Затем в вашем классе:

public class CommandDispatcher : ICommandDispatcher
{
    private ICommandHandlerFactory commandHandlerFactory;

    public CommandDispatcher(ICommandHandlerFactory commandHandlerFactory)
    {
        this.commandHandlerFactory = commandHandlerFactory;
    }

    public void Dispatch<T>(T command)
    {
        var commandHandler = commandHandlerFactory.Create<T>();
        commandHandler.Handle(command);
    }
}
person Patrick Quirk    schedule 15.09.2014
comment
Это именно то, что я искал, но я не знал, что вы можете создать фабрику объектов, используя общие свойства дженериков. Спасибо. - person Raffaeu; 16.09.2014

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

Другими словами, пока ваш CommandDispatcher является частью корня композиции (и содержит только инфраструктуру, а не бизнес-логику), можно позволить ему зависеть от контейнера.

person Steven    schedule 15.09.2014
comment
Спасибо за ответ, Стивен, это было моей главной заботой, чтобы не прыгнуть в анти-шаблон Service Locator. - person Raffaeu; 16.09.2014