【发布时间】:2014-05-22 14:56:12
【问题描述】:
我在设置命令处理架构时遇到了一些问题。我希望能够创建许多从 ICommand 派生的不同命令;然后,创建多个从 ICommandHandler 派生的不同命令处理程序;
这是我已经开始定义的接口和类:
interface ICommand {}
class CreateItemCommand : ICommand {}
interface ICommandHandler<TCommand> where TCommand : ICommand {
void Handle(TCommand command);
}
class CreateItemCommandHandler : ICommandHandler<CreateItemCommand> {
public void Handle(CreateItemCommand command) {
// Handle the command here
}
}
我有一个可以创建适当类型命令的辅助类:
class CommandResolver {
ICommand GetCommand(Message message) {
return new CreateItemCommand(); // Handle other commands here
}
}
还有一个帮助类,用于创建适当的处理程序;这就是我遇到麻烦的地方:
class CommandHandlerResolver {
public ICommandHandler<TCommand> GetHandler<TCommand>(TCommand command) {
// I'm using Ninject and have an instance of an IKernel
// The following code throws an exception despite having a proper binding
// _kernel.GetService(typeof(ICommandHandler<TCommand>))
var bindingType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
var handler = _kernel.GetService(bindingType);
return handler as ICommandHandler<TCommand>;
// handler will be null after the cast
}
}
这里是主要的运行方法
CommandResolver _commandResolver;
HandlerResolver _handlerResolver;
void Run() {
// message is taken from a queue of messages
var command = _commandResolver.GetCommand(message);
var handler = _handlerResolver.GetHandler(command);
// handler will always be null
handler.Handle(command);
}
我可以想出几种不同的方法来重构代码,我确信可以避免这个问题,但我发现自己对这个问题有点困惑,想了解更多发生的事情。
这个设计看起来应该可行。
【问题讨论】:
-
1)
handler as CommandHandler<TCommand>;为什么要转换到类,而不是接口? 2) 为什么是as演员?演员阵容不应该失败。 |将其替换为return (ICommandHandler<TCommand>)handler; -
考虑 1) 将
ICommandHandler替换为代表。 2) 考虑将其TCommand类型参数设为in参数(逆变)。 -
我试图使 TCommand 逆变,但它没有效果。据我了解,这只会影响我将通用 ICommandHandler 类型作为参数传递给方法,而不是我怀疑我遇到的分配问题,即将 CreateItemCommandHandler 分配给 ICommandHandler
。 -
@Sambo 是的,当你有应该处理
CreateItem命令的东西时会发生什么?例如缓存操作以及您的业务逻辑或记录器。CreateItemHandler2?始终以组件的功能命名组件,而不是它们的使用方式 -
@GeorgeMauer 我认为这里的设计意味着每个命令类型必须有一个处理程序,该处理程序的工作是执行该命令。缓存操作或日志记录等其他问题不会使用
ICommandHandler机制,而是使用其他方式,例如ICommandHandlingInterceptor或其他。从一般意义上说,根据用途而不是用途来命名事物是正确的,但这里两者是相同的。
标签: c# generics architecture covariance contravariance