【问题标题】:Windsor Castle/ DI and object models温莎城堡/ DI 和对象模型
【发布时间】:2013-06-14 13:26:28
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

  • 您链接到命令/处理程序模式的描述(使用ICommandHandler<T>),但实际上您使用的是命令模式,这是完全不同的,因为命令/处理程序模式中的命令是没有行为的 DTO,它们不包含 Execute 方法。在它们上使用Execute 方法会禁用命令/处理程序模式带来的大部分功能。当您将依赖项注入处理程序时,将依赖项注入命令的问题将消失。在命令/处理程序模式中,命令没有任何依赖关系(因为它们没有任何行为)。
  • 感谢您的回答,史蒂文。你当然是对的,我可以将它们注入处理程序。但这并不能解决问题,因为我仍然必须注入相同的信息并调用容器以使我的数据可供处理程序使用。不可能批处理命令并连续执行它们。我有什么问题吗?

标签: command castle-windsor castle


【解决方案1】:

基础设施:

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

【讨论】:

  • 马吕斯,非常感谢。相当全面。会试一试!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多