2013-05-29 71 views
2

我必須設計一個Command/CommandHandler模​​塊,並且正在努力設計的細節。C#泛型/ ICommandHandler/ICommand設計

我已經創建了一個(空)接口:

public interface ICommand {} 

其通過各種命令來實現,

例如

public interface TestCommand : ICommand {} 

一個(或多個)CommandHandlers可以註冊爲ICommand的特定實現。爲了避免不斷鑄造我已經建立了一個接口:

public interface ICommandHandler<in TCommand> 
     where TCommand : ICommand 
{ 
    void Handle(TCommand command); 
} 

到目前爲止好...指揮調度系統是令人不安的東西:命令處理程序應該由Autofac注入(或任何其他DI系統),例如:

public CommandDispatcher (IEnumerable<ICommandHandler<ICommand>> commandHandlers) 

正如你所看到的,這是不可能的。 ICommandHandler<CommandType1>ICommandHandler<CommandType2>不是從ICommandHandler<ICommand>派生的,因此不能放入相同的IEnumerable。

任何建議如何在一個沒有問題的方式來設計這個?

回答

2

通常你會在調用它們之前解決它們。例如,在Autofac

class CommandDispatcher 
{ 
    private readonly Autofac.IComponentContext context; // inject this 

    public void Dispatch<TCommand>(TCommand command) 
    { 
     var handlers = context.Resolve<IEnumerable<ICommandHandler<TCommand>>>(); 
     foreach (var handler in handlers) 
     { 
      handler.Handle(command); 
     } 
    } 

    public void ReflectionDispatch(ICommand command) 
    { 
     Action<CommandDispatcher, ICommand> action = BuildAction(command.GetType()); 
     // see link below for an idea of how to implement BuildAction 

     action(this, command); 
    } 
} 

如果你需要方法的簽名更改爲Dispatch(ICommand command),看this answer。你應該能夠適應你的情況。

+0

對我來說,在任何地方注入容器看起來是一個非常糟糕的做法。這不應該只發生在頂層? –

+0

如果可能,我們還想使用Dispatch(ICommand命令)。 –

+0

您不會將容器「無處不在」注入,只能注入特定的基礎結構代碼段。只要很小比例的代碼引用容器,就沒有問題。有些人會建議定義'ICommandDispatcher',然後在組合根目錄下創建一個'AutofacCommandDispatcher',但我認爲這是不必要的間接 - 如果切換DI容器,則工作量相同;唯一的優點是如果您不想在「業務邏輯」程序集中引用Autofac DLL。 –