命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
代码如下:
1 /** 2 * 抽象命令角色类 3 */ 4 public interface Command { 5 /** 6 * 执行方法 7 */ 8 void execute(); 9 }
1 /** 2 * 接收者角色类 3 */ 4 public class Receiver { 5 /** 6 * 真正执行命令相应的操作 7 */ 8 public void action(){ 9 System.out.println("执行操作"); 10 } 11 }
1 /** 2 * 具体命令角色类 3 */ 4 public class ConcreteCommand implements Command { 5 6 //持有相应的接收者对象 7 private Receiver receiver = null; 8 9 /** 10 * 构造方法 11 * 12 * @param receiver 13 */ 14 public ConcreteCommand(Receiver receiver) { 15 this.receiver = receiver; 16 } 17 18 19 @Override 20 public void execute() { 21 //通常会转调用接收者对象的相应方法,让接收者来真正执行功能 22 receiver.action(); 23 } 24 }
1 /** 2 * 请求者角色类 3 */ 4 public class Invoker { 5 /** 6 * 持有命令对象 7 */ 8 private Command command=null; 9 10 /** 11 * 构造方法 12 * @param command 13 */ 14 public Invoker(Command command) { 15 this.command = command; 16 } 17 18 /** 19 * 行动方法 20 */ 21 public void action(){ 22 command.execute(); 23 } 24 }
1 /** 2 * 客户端 3 */ 4 public class Client { 5 public static void main(String[] args) { 6 //创建接收者 7 Receiver receiver=new Receiver(); 8 //创建命令对象,设定它的接收者 9 Command command=new ConcreteCommand(receiver); 10 //创建请求者,把命令对象设置进去 11 Invoker invoker=new Invoker(command); 12 //执行方法 13 invoker.action(); 14 } 15 }
以下例子是《大话设计模式》中的例子:
1 /** 2 * 烤串者(命令执行者) 3 */ 4 public class Barbecuer { 5 public void bakeMutton(){ 6 System.out.println("烤羊肉串"); 7 } 8 public void bakeChickenWing(){ 9 System.out.println("烤鸡翅"); 10 } 11 }
1 /** 2 * 抽象命令类 3 */ 4 public abstract class Command { 5 //抽象命令类,只需要确定‘烤肉串者'是谁 6 protected Barbecuer receiver; 7 8 /** 9 * 10 * @param receiver 参数为命名执行人 11 */ 12 public Command(Barbecuer receiver) { 13 this.receiver = receiver; 14 } 15 16 //执行命令 17 abstract public void excuteCommand(); 18 }
1 /** 2 * 烤鸡翅命令 3 */ 4 public class BakeChickenWingCommand extends Command { 5 public BakeChickenWingCommand(Barbecuer receiver) { 6 super(receiver); 7 } 8 9 @Override 10 public void excuteCommand() { 11 receiver.bakeChickenWing(); 12 } 13 }
1 /** 2 * 烤羊肉串命令 3 */ 4 public class BakeMuttonCommand extends Command { 5 6 public BakeMuttonCommand(Barbecuer receiver) { 7 super(receiver); 8 } 9 10 @Override 11 public void excuteCommand() { 12 receiver.bakeMutton(); 13 } 14 }
1 /** 2 * 服务员类 3 */ 4 public class Waiter { 5 private List<Command> orders=new ArrayList<>(); 6 /** 7 * 不管用户想要什么烤肉,反正都是命令,只管记录订单,然后通知烤肉者执行 8 * @param command 9 */ 10 public void setOrder(Command command){ 11 orders.add(command); 12 System.out.println("增加订单:"+command.toString()+" 时间:"+new Date()); 13 } 14 public void cancelOrder(Command command){ 15 orders.remove(command); 16 System.out.println("取消订单:"+command.toString()+" 时间:"+new Date()); 17 } 18 //通知执行 19 public void notifyExcuteCommand(){ 20 for (Command command:orders 21 ) { 22 command.excuteCommand(); 23 } 24 25 } 26 }
1 public class Client { 2 public static void main(String[] args) { 3 //命令执行人 4 Barbecuer boy=new Barbecuer(); 5 Command bakeMuttonCommand1=new BakeMuttonCommand(boy); 6 Command bakeMuttonCommand2=new BakeMuttonCommand(boy); 7 Command bakeChickenWingCommand1=new BakeChickenWingCommand(boy); 8 //命令布人 9 Waiter girl=new Waiter(); 10 11 //开门营业 12 //记录订单命令 13 girl.setOrder(bakeMuttonCommand1); 14 girl.setOrder(bakeMuttonCommand2); 15 girl.setOrder(bakeChickenWingCommand1); 16 17 //点菜完毕,通知厨房(下达命令) 18 girl.notifyExcuteCommand(); 19 girl.cancelOrder(bakeChickenWingCommand1); 20 } 21 }
命令模式作用
第一,它能较容易地设计一个命令队列;
第二,在需要的情况下,可以较容易地将命令记入日志;
第三,允许接收请求的一方决定是否要否决请求。
第四,可以容易地实现对请求的撤销和重做。
第五,由于加新的具体命令类不影响其他类,因此增加新的具体命令类很容易。
命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。