一,定义
命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
Command类,用来声明执行操作的接口
ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接受者相应的操作,以实现execute
invoker类,要求该命令执行这个请求。
receiver类,知道如何实施与执行一个请求相关的操作,任何类都可能作为一个接受者。
二,实例
实现一个顾客吃烧烤的例子。
/**
* @类描述:烤肉串者
*/
public class Barbecuer {
public void bakeMutton(){
System.out.println("烤羊肉串!");
}
public void bakeChickenWing(){
System.out.println("烤鸡翅!");
}
}
/**
* @类描述:抽象命令
*/
public abstract class Command {
protected Barbecuer barbecuer;
public Command(Barbecuer barbecuer){
this.barbecuer = barbecuer;
}
public abstract void excuteCommand();
}
/**
* @类描述:烤鸡翅命令
*/
public class BakeChickenWingCommand extends Command{
public BakeChickenWingCommand(Barbecuer barbecuer) {
super(barbecuer);
}
@Override
public void excuteCommand() {
barbecuer.bakeChickenWing();
}
}
/**
* @类描述:烤肉串命令
*/
public class BakeMuttonCommand extends Command{
public BakeMuttonCommand(Barbecuer barbecuer) {
super(barbecuer);
}
@Override
public void excuteCommand() {
barbecuer.bakeMutton();
}
}
/**
* @类描述:服务员
*/
public class Waiter {
private List<Command> orders = new ArrayList<>();
public void setOrder(Command command) {
if (command instanceof BakeChickenWingCommand) {
System.out.println("服务员:鸡翅没有了,请点其他烧烤!");
} else {
orders.add(command);
System.out.println("日志:增加订单。时间:" + System.currentTimeMillis());
}
}
public void removeOrder(Command command) {
orders.remove(command);
}
public void notifyOrders() {
for (Command command : orders) {
command.excuteCommand();
}
}
}
//test main
//命令模式
public static void commandModel(){
Barbecuer barbecuer = new Barbecuer();
Command muttonCommand1 = new BakeMuttonCommand(barbecuer);
Command muttonCommand2 = new BakeMuttonCommand(barbecuer);
Command chickenCommand = new BakeChickenWingCommand(barbecuer);
Waiter waiter = new Waiter();
//顾客点餐
waiter.setOrder(muttonCommand1);
waiter.setOrder(muttonCommand2);
waiter.setOrder(chickenCommand);
waiter.notifyOrders();
}
输出结果:
日志:增加订单。时间:1528169534816
日志:增加订单。时间:1528169534816
服务员:鸡翅没有了,请点其他烧烤!
烤羊肉串!
烤羊肉串!
三,总结
优点:
- 它能较容易地设计一个命令队列
- 在需要的情况下,可以较容易地将命令队列记入日志
- 允许接收请求的一方决定是否要否决请求
- 可以容易地实现对请求的撤销和重做
- 由于加进新的具体命令类不影响其他的类,因此增加新的命令类很容易
- 把请求一个操作的对象与指导怎么执行一个操作的对象分隔开
适用场景:
- 对于大多数请求-响应模式的功能,比较适合使用命令模式,正如命令模式定义说的那样,命令模式对实现记录日志、撤销操作等功能比较方便。
敏捷开发的原则告诉我们,不要为代码添加基于猜测的,实际不需要功能,如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候重构实现这个模式并不难,只有在真正需要如撤销,恢复操作等功能时,把原来的代码重构为命令模式才有意义。
参考:《大话设计模式》