命令模式
命令模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。(行为类模式)
结构图
代码实现
抽象命令类Command
/**
* 声明命令,对外公布
*
* @author xukai 2016年3月30日 下午11:27:18
*
*/
public abstract class Command {
public abstract void execute();
}
/**
* 调用者,调用命令
*
* @author xukai 2016年3月30日 下午11:28:04
*
*/
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action() {
command.execute();
}
}
接受者Receiver
/**
* 接受者,负责接受命令和执行命令
*
* @author xukai 2016年3月30日 下午11:29:07
*
*/
public class Receiver {
public void doSomething() {
System.out.println("接受者-业务逻辑处理");
}
}
命令类:ConcreteCommand
/**
* 具体命令的实现
*
* @author xukai 2016年3月30日 下午11:33:40
*
*/
public class ConcreteCommand extends Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
super();
this.receiver = receiver;
}
@Override
public void execute() {
receiver.doSomething();
}
}
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
// 直接执行命令
command.execute();
// 通过调用者执行命令
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
输出:
接受者-业务逻辑处理
接受者-业务逻辑处理
demo
问题:烧烤店点菜。
结构图
代码实现
抽象命令Command
/**
* 抽象命令
*
* @author xukai 2016年3月30日 下午11:53:19
*
*/
public abstract class Command {
protected Barbecuer barbecuer;
public Command(Barbecuer barbecuer) {
super();
this.barbecuer = barbecuer;
}
public abstract void excutedCommand();
}
具体命令
/**
* 烤羊肉串命令
*
* @author xukai 2016年3月30日 下午11:57:01
*
*/
public class BakeMuttonCommand extends Command {
public BakeMuttonCommand(Barbecuer barbecuer) {
super(barbecuer);
}
@Override
public void excutedCommand() {
barbecuer.bakeMutton();
}
}
/**
* 烤鸡翅命令
*
* @author xukai 2016年3月30日 下午11:58:04
*
*/
public class BakeChickenWingCommand extends Command {
public BakeChickenWingCommand(Barbecuer barbecuer) {
super(barbecuer);
}
@Override
public void excutedCommand() {
barbecuer.bakeChickenWing();
}
}
烤肉者:
/**
* 做烧烤的人:请求的的处理者
*
* @author xukai 2016年3月30日 下午11:54:38
*
*/
public class Barbecuer {
public void bakeMutton() {
System.out.println("烤羊肉串");
}
public void bakeChickenWing() {
System.out.println("烤鸡翅");
}
}
/**
* 服务员:请求接受者
*
* @author xukai 2016年3月30日 下午11:58:36
*
*/
public class Waiter {
private List<Command> orders = new ArrayList<>();
public void setOrder(Command command) {
orders.add(command);
System.out.println("增加订单:" + command.toString() + ",时间: " + (new Date()));
}
public void cancle(Command command) {
orders.remove(command);
System.out.println("取消订单:" + command.toString() + ",时间 :" + (new Date()));
}
public void resolve() {
for (Command command : orders) {
command.excutedCommand();
}
}
}
客户端:
public class Client {
public static void main(String[] args) {
// 开店准备
// 烧烤师
Barbecuer barbecuer = new Barbecuer();
// 提供命令
Command bakeMuttonCommand1 = new BakeMuttonCommand(barbecuer);
Command bakeMuttonCommand2 = new BakeMuttonCommand(barbecuer);
Command bakeChickenWingCommand1 = new BakeChickenWingCommand(barbecuer);
Waiter waiter = new Waiter();
// 服务员添加菜单
waiter.setOrder(bakeMuttonCommand1);
waiter.setOrder(bakeMuttonCommand2);
waiter.setOrder(bakeChickenWingCommand1);
// 菜单交给烧烤师
waiter.resolve();
// 客人该主意了,不要鸡翅了
waiter.cancle(bakeChickenWingCommand1);
// 菜单交给烧烤师
waiter.resolve();
}
}
客户端输出:
增加订单:com.xk.day0330.command.demo.BakeMuttonCommand@41a7d9e7,时间: Thu Mar 31 00:14:16 CST 2016
增加订单:com.xk.day0330.command.demo.BakeMuttonCommand@360088ee,时间: Thu Mar 31 00:14:18 CST 2016
增加订单:com.xk.day0330.command.demo.BakeChickenWingCommand@5d1ddcf4,时间: Thu Mar 31 00:14:18 CST 2016
烤羊肉串
烤羊肉串
烤鸡翅
取消订单:com.xk.day0330.command.demo.BakeChickenWingCommand@5d1ddcf4,时间 :Thu Mar 31 00:14:18 CST 2016
烤羊肉串
烤羊肉串
把吃烧烤分成了三步:客户点菜,服务员记录菜单,烧烤师做烧烤,实现了松耦合。
总结
优点(封装性好,扩展性好)
1.容易形成命令队列;
2.命令可以写入日志;
3.允许接受请求的一方决定是否要否决请求(如:烤肉卖完了);
4.可以实现撤销和重做;
5.各个具体命令类相互之间不影响;
缺点
命令假如过多,那么每一个命令都需要一个命令类封装,哪怕只是很简单的命令或者几行代码的事。
核心:把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
敏捷开发原则
不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般不要着急去实现它,事实上,在需要的时候通过重构实现并不困难,只有在真正需要撤销、恢复等功能时,重构原来代码为命令模式才有意义。