命令模式
定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
使用场景
对于请求排队或记录请求日志,以及支持可撤销的操作等行为时,行为请求者和行为实现者的紧耦合时不太适合的。
根据敏捷开发原则我们知道,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
优点:
- 容易设计一个命令队列
- 在需要的情况下,可以较容易的将命令计入日志
- 允许接收请求的一方决定是否要否决请求
- 可以容易地实现对请求的撤销和重做
- 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易
- 把请求一个操作的对象与知道怎么执行一个操作对象分割开
UML图
用例
烤肉店点餐
烤串者类
public class Barbecuer{
public void BakeMutton(){
System.out.println("烤羊肉串");
}
public void BakeChickenWing(){
System.out.println("烤鸡翅");
}
}
抽象命令类
public abstract class Command{
protected Barbecuer receiver;
public Command(Barbecuer receiver){
this.receiver = receiver;
}
abstract public void excuteCommand();
}
详细命令类
//烤羊肉串命令
class BakeMuttonCommand extends Command {
public BakeMuttonCommand (Barbecuer receiver){
super(receiver);
}
@override
public void excuteCommand(){
receiver.BakeMutton();
}
}
//烤鸡翅命令
class BakeChickenWingCommand extends Command{
public BakeChickenWingCommand(Barbecuer receiver){
super(receiver);
}
@override
public void excuteCommand(){
receiver.BakeChickenWing();
}
}
服务员类
public class Waiter{
private IList<Command> orders = new List<Command>();
//设置订单
public void setOrder(Command command){
if (command.toString() == "命令模式.BakeChickenWingCommand"){
System.out.println("服务员:鸡翅没有了,请点别的烧烤");
}
else{
orders.add(command);
System.out.println("添加订单:" + command.ToString() + "时间:" + DateTime.Now.ToString());
}
}
//取消订单
public void cancelOrder(Command command){
orders.remove(command);
System.out.println("取消订单:" + command.ToString() + "时间:" + DateTime.Now.ToString());
}
//通知所有运行
public void notify(){
foreach (Command cmd in orders){
cmd.excuteCommand();
}
}
}
客户端
static void Main(string[] args){
//开店前的准备
Barbecuer boy = new Barbecuer();
Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter girl = new Waiter();
//开门营业,顾客点菜
girl.SetOrder(bakeMuttonCommand1);
girl.SetOrder(bakeChickenWingCommand1);
//点菜完成。通知厨房做菜
girl.Notify();
}