命令对象模式想要还是真实的东西?

Ser*_*ero 6 c# design-patterns

命令对象模式是我仍然无法真正掌握的模式,我在目前正在编写的代码中找到了一个实现,因此我研究了很长时间并且很难看到我是否能够在现实世界中获得它例.问题是,我确信这没有得到正确实施,只是一个刚刚阅读过它的人尝试并认为这里有意义.

请允许我向您展示(出于保密原因,它将大大简化,但我会尽力展示主要概念):

public class CommandOne
{
   public CommandOne(Manager manager, MyForm form)
   {
      m_manager = manager;
      m_form = form;
   }

   public void Execute()
   {
       m_manager.CommandOne(m_form);
   }
}

public class CommandTwo
{
   public CommandTwo(Manager manager, MyForm form)
   {
      m_manager = manager;
      m_form = form;
   }

   public void Execute()
   {
       m_manager.CommandTwo(m_form);
   }
}
Run Code Online (Sandbox Code Playgroud)

令我感到奇怪的第一件事是这两个类不是从任何抽象类继承,也不是实现公共接口.

使用这些命令的代码如下:

public class MyForm : System.Windows.Forms.Form
{
   public MyForm(Manager manager)
   {
      m_manager = manager;
   }

   private void SomeMethod()
   {
      ....
      var cmd = new CommandOne(manager, this);
      cmd.Execute();
      ...
   }

   private void OtherMethod()
   {
      ....
      var cmd = new CommandTwo(manager, this);
      cmd.Execute();
      ...
   }
}
Run Code Online (Sandbox Code Playgroud)

所以我看到它的方式,这个表单绝对耦合到所有涉及的类,除了通过其构造函数注入它的管理器.所以使用这段代码我真的没有看到创建"命令"类的任何好处,这些类基本上只是委托调用管理器的方法,因为表单在需要时实例化它们并且之后调用execute方法.

那么有人可以解释一下,如果有的话,这个实现缺少真正的命令对象模式,虽然它可能过于主观,但在这种情况下实现它有什么好处?

谢谢.

Mik*_*nty 11

根据您在此处显示的内容,看起来命令模式的好处已丢失.您可能希望在WinForms应用程序的上下文中使用命令模式有几个原因.

您想稍后执行命令

public interface ICommand
{
    void Execute();
}
Run Code Online (Sandbox Code Playgroud)

保留已执行命令的历史记录,以便用户可以撤消它们

public interface ICommand
{
    void Execute();

    void Undo();
}
Run Code Online (Sandbox Code Playgroud)

检查权限以查看当前用户是否有权执行该命令.例如,您可能拥有RefundCustomerCommand并且并非所有客户服务代理都有权发出退款,因此您要禁用表单上的按钮.

public interface ICommand
{
    void Execute();

    bool CanExecute { get; }
}
Run Code Online (Sandbox Code Playgroud)

您还可以在组合中滚动多个命令,如下所示:

public class CompositeCommand : ICommand
{
    private readonly List<ICommand> commands;

    public CompositeCommand()
    {
        commands = new List<ICommand>();
    }

    public void Add(ICommand command)
    {
        commands.Add(command);
    }

    public void Execute()
    {
        foreach (var command in commands) command.Execute();
    }
}
Run Code Online (Sandbox Code Playgroud)

命令模式也可以很好地与装饰器配合使用.您可以轻松地为命令添加其他横切行为,例如重试逻辑:

public class RetryOnTimeout : ICommand
{
    private readonly ICommand command;
    private int numberOfRetries;

    public RetryOnTimeout(ICommand command, int numberOfRetries)
    {
        this.command = command;
        this.numberOfRetries = numberOfRetries;
    }

    public void Execute()
    {
        try
        {
            command.Execute();
        }
        catch (TimeoutException)
        {
            if (++numberOfRetries > 3)
                throw;

            Execute();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)