5

我现在使用温莎城堡有一段时间了。它非常适合数据位于数据库等的环境,其中存储库模式或工作单元模式运行良好。

现在我确实有不同的情况:我有一个由许多单个 PONO 组装的复杂对象模型。环境受到 COM 的强烈影响,使其更加明确:Excel、Word PIO 被大量使用。

我确实使用命令模式,我实现了这里描述的 ICommandHandler,但有一个区别。由于我确实想将命令组装到命令列表中以在运行中调用它们而不知道所描述的一般命令模式之外的任何内容,因此在调用执行方法时不会引入上下文。所以界面看起来是这样的:

    public interface ICommand
    {
        void Execute();
        bool CanExecute();
    }

使用该界面执行命令是有效且易于理解的。另一方面,使用 ctor 引入上下文是一个问题,因为因此必须显式调用 Container 以添加 ctor 参数。

所以我实际上有两个问题:

  1. 是否可以在不显式调用容器的情况下由温莎城堡自动注入一个 - 我们称之为上下文,对象模型的一部分?
  2. 如何使用 DI 参与命令模式?任何想法如何通过遵循此处描述的 RRR 规则来定义任务/操作列表等?
4

1 回答 1

4

基础设施:

public interface ICommandHandler<in T>
{
    void Handle(T command);
}

public interface ICommandExecutor
{
    CommandResult ExecuteCommand(Command command);
    CommandResult ExecuteCommands(Command[] commands);
}

public abstract class Command
{

}

public class CommandExecutor : ICommandExecutor
{
    private readonly IWindsorContainer _kernel;

    public CommandExecutor(IWindsorContainer kernel)
    {
        Guard.AssertNotNull(() => kernel);
        _kernel = kernel;
    }

    public CommandResult ExecuteCommand(Command command)
    {
        return ExecuteInternal(command);
    }

    public CommandResult ExecuteCommands(Command[] commands)
    {
        CommandResult result = null;

        foreach (Command command in commands)
        {
            result = ExecuteInternal(command);

            if (!result.IsExecuted)
                return result;
        }

        return result ?? CommandResult.Executed("Command executed successfully");
    }

    private CommandResult ExecuteInternal(Command command)
    {
        dynamic handler = FindHandlerForCommand(command);

        try
        {
            handler.Handle(command as dynamic);
            return CommandResult.Executed("Command executed successfully");
        }
        finally
        {
            _kernel.Release(handler);
        }
    }

    private object FindHandlerForCommand(Command command)
    {
        Type handlerType = typeof (ICommandHandler<>).MakeGenericType(command.GetType());
        dynamic handler = _kernel.Resolve(handlerType);
        return handler;
    }
}

登记:

        container.Register(Component.For<ICommandExecutor>().ImplementedBy<CommandExecutor>()
            .Interceptors<ExceptionToCommandResult>()
            .Interceptors<ExceptionLogger>()
            .Interceptors<HandleWhenDeadlockVictim>()
            .Interceptors<RetryCommand>()
            .Interceptors<ContainerScopeWrapper>()
            .Interceptors<TransactionWrapper>()
            .Interceptors<SameNhibernateSessionAndTransactionWrapper>());

例子:

public class WriteComment : Command
{
    public string GameToCommentId { get; set; }

    public string Comment { get; set; }
}

public class WriteCommentCommandHandler : ICommandHandler<WriteComment>
{
    private readonly IGameRepository _repository;

    public WriteCommentCommandHandler(IGameRepository repository)
    {
        Guard.AssertNotNull(() => repository);
        _repository = repository;
    }

    public void Handle(WriteComment command)
    {
        var game = _repository.Get(new Guid(command.GameToCommentId));

        game.WriteComment(command.Comment, DateTime.Now);
    }
}

所有 AOP 的东西都处理事务等等。命令执行器是一个无状态的单例,处理程序指定它们的不同需求。命令执行器只是基础设施和域无关,所以将它放在你喜欢的域之外的地方。这是一个大系统上的生产代码,就像一个魅力。

于 2013-06-24T14:29:25.607 回答