定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤销操作。
使用场景
认为是命令的地方都可以使用命令模式,日落 GUI中的每个按钮都是一条命令,模拟cmd
- 用户点餐,电视遥控器
- 系统需要支持命令的撤销和恢复操作也可考虑用命令模式
- 在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- 敏捷开发原则告诉我们,不要为代码添加基于猜测、实际不需要的功能。
如果不清楚一个系统是否需要命令模式,不要着急去实现。实现命令模式不难,只有当需要命令模式时,重构才有意义
代码实现
//抽象命令类
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
public abstract void ExecuteCommand();
}
//具体命令类
class ConcreteCommand: Command
{
public ConcreteCommand(Receiver receiver): base(receiver) { }
public override void ExecuteCommand()
{
receiver.Action();
}
}
//执行者
//执行 和 撤销(结合备忘录模式 还原状态)
//Command 可使用列表,日志功能
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExcuteCommand()
{
command.ExcuteCommand();
}
}
//命令接收者
class Receiver
{
public void Action()
{
//执行命令
}
}
void Main()
{
Receiver receiver = new Receiver(); //命令接收者
Command Com1 = new ConcreteCommand(receiver); //具体命令
Invoker invoker = new Invoker(); //命令发起者
invoker.SetCommand(com1); //下令
invoker.ExcuteCommand(); //执行命令
}
// 执行者 -> 具体命令 -> 接收者优点&缺点
- 较容易设计一个命令队列
- 在需要的情况下,可以较容易地将命令记录日志
- 允许接收请求的一方决定是否要否决请求
- 可以容易实现对请求的撤销和重做
- 加入新的请求不会影响其他的类,因此增加新的具体命令类和容易
- 最关键的优点 命令模式把一个操作的对象 与 知道怎么执行一个操作的对象分隔开
- 使用命令模式可能会导致某些系统有过多的具体命令类。