命令对象模式是我仍然无法真正掌握的模式,我在我正在编写的代码中找到了一个实现,所以我研究了很长时间,很难看出我是否能够最终得到它一个现实世界的例子。问题是我确信这没有得到适当的实施,只是一个刚刚阅读过它的人尝试并认为它在这里有意义。
请允许我向您展示(出于保密原因,它会大大简化,但我会尽力展示主要概念):
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);
}
}
令我感到奇怪的第一件事是,这两个类不是从任何抽象类继承,也不是实现公共接口。
使用这些命令的代码如下:
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();
...
}
}
所以我看到它的方式,这个表单绝对耦合到所有涉及的类,除了通过其构造函数注入它的管理器。所以使用这段代码我真的没有看到创建“命令”类的任何好处,这些类基本上只是委托调用管理器的方法,因为表单在需要时实例化它们并且之后调用execute方法。
那么有人可以解释一下,如果有的话,这个实现缺少真正的命令对象模式,尽管它可能过于主观,在这种情况下实现它会有什么好处?
谢谢。
答案 0 :(得分:11)
根据您在此处显示的内容,看起来命令模式的好处已丢失。您可能希望在WinForms应用程序的上下文中使用命令模式有几个原因。
您想稍后执行命令
public interface ICommand
{
void Execute();
}
保留已执行命令的历史记录,以便用户可以撤消
public interface ICommand
{
void Execute();
void Undo();
}
检查权限以查看当前用户是否有权执行该命令。例如,您可能拥有RefundCustomerCommand
并且并非所有客户服务代理都有权发出退款,因此您要禁用表单上的按钮。
public interface ICommand
{
void Execute();
bool CanExecute { get; }
}
您还可以在这样的组合中滚动多个命令:
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();
}
}
命令模式也可以很好地与装饰器配合使用。您可以轻松地为命令添加其他横切行为,例如重试逻辑:
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();
}
}
}