初识
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
结构
角色:
- Invoker类:要求该命令执行这个请求
- Command类:用来声明执行操作的抽象类或接口
- ConcreteCommand类:将一个接受者对象绑定于一个动作,调用接收者相应的操作,以实现Execute
- Receiver类:知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接受者
应用
背景:烧烤店中,顾客到了店里,由服务员负责记录顾客的点菜情况,再将顾客点的餐告诉厨师,厨师进行制作。这里,顾客与厨师进行解耦,服务员相当于Invoker类,是命令的传达者;将每一桌顾客的请求封装为一个对象,类似于ConcreteCommand类;厨师是命令的接受者,相当于Receiver类。
class Program
{
static void Main(string[] args)
{
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
girl.SetOrder(bakeMuttonCommand1);
girl.SetOrder(bakeMuttonCommand2);
girl.SetOrder(bakeChickenWingCommand1);
girl.Notify();
Console.Read();
}
}
public class Barbecuer//烤羊肉串者
{
public void BakeMutton()
{
Console.WriteLine("烤羊肉串!");
}
public void BackChickenWing()
{
Console.WriteLine("烤鸡翅!");
}
}
public abstract class Command//抽象命令类
{
protected Barbecuer receiver;
public Command(Barbecuer receiver)
{
this.receiver = receiver;
}
abstract public void ExcuteCommand();//执行命令
}
class BakeMuttonCommand : Command//烤羊肉串命令
{
public BakeMuttonCommand(Barbecuer receiver) : base(receiver)
{
}
public override void ExcuteCommand()
{
receiver.BakeMutton();
}
}
class BakeChickenWingCommand : Command//烤鸡翅命令
{
public BakeChickenWingCommand(Barbecuer receiver) : base(receiver)
{
}
public override void ExcuteCommand()
{
receiver.BackChickenWing();
}
}
public class Waiter//服务员类
{
private IList<Command> orders = new List<Command>();
public void SetOrder(Command command)//判断顾客点的是否是烤鸡翅
{
if (command.ToString()=="命令模式.BakeChickenWingCommand")
{
Console.WriteLine("服务员:鸡翅没有了,请点别的烧烤。");
}
else
{
orders.Add(command);
Console.WriteLine("增加订单:"+command.ToString()+"时间:"+DateTime.Now.ToString());
}
}
public void CancelOrder(Command command)//取消订单
{
orders.Remove(command);
Console.WriteLine("取消订单:"+command.ToString()+"时间:"+DateTime.Now.ToString());
}
public void Notify()
{
foreach (Command cmd in orders)
{
cmd.ExcuteCommand();
}
}
}
优点
- 类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
- 可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。
- 命令模式结合其他模式会更优秀:命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少 Command子类的膨胀问题。
缺点
- 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
应用场景
a、系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
b、系统需要在不同的时间指定请求、将请求排队和执行请求。
c、系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
d、系统需要将一组操作组合在一起,即支持宏命令。