Java设计模式之命令模式
2016-06-09 12:07
579 查看
当一系列的类能直接找到我,让我帮他们干活时,其实我是拒绝的。我又要接待你们(接收命令),又要干活(执行命令),真是麻烦。自从我有了一个秘书之后,事情就好办多了,因为我再也不需要接待别的类了,因为秘书能帮我接收命令,把方法调用(method invocation)封装起来了,而且我和秘书的耦合程度也很低哦。(解耦)
![](http://img.blog.csdn.net/20160609121426843)
命令模式结构代码:
1)命令抽象类,用来声明操作的接口(interface会更好)
2)具体命令类,将一个接受者绑定于一个动作,调用接受者相应的操作,以实现Execute(一系列操作)
3)传达者,要求该命令执行这个或一系列请求
4)接收者,知道如何实施与执行一个与请求相关的操作
5)命令接受及执行过程
命令模式的要点:
I. 命令模式将发出请求的对象和执行请求的对象解耦。
II. 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。
III. 调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用(命令可以支持撤销)。
IV. 宏命令是命令的一种延伸,允许调用多个命令。
V. 命令也可以用来实现日志和事务系统。
2)抽象命令类,关于烧烤的命令
3)具体命令类,执行命令时,执行具体的行为,烤不同的食材。(如烤鸡翅)
4)具体命令类,宏命令。执行此命令时,会执行一系列命令。
5)传递者类,传达请求,与请求者及执行者都解耦了。此处即为服务员。
6)客户端,即完成命令模式的系统或插件。此处为烧烤店。
7)运行结果,当命令类名为烤鸡翅时,显示无存货。(实际应用时可在客户端,即烧烤店里记录存货以对比库存)
![](http://img.blog.csdn.net/20160609162743356)
2)能将命令记入日志,并以此来支持撤销功能;
3)加入新的具体命令类不影响其他的类,因此增加新的命令类很容易;
4)封装方法调用中的五点要点。
注意:
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。(自大话设计模式)
参考资料:
1.《Head First设计模式》
2.《大话设计模式》
1. 命令模式
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。2. 封装方法调用
命令对象不直接实现execute()方法的细节。尽量设计“傻瓜”命令对象,它只懂得调用一个接受者的一个行为,能使调用者和接受者之间的解耦程度比设计聪明的命令对象高。命令模式结构代码:
1)命令抽象类,用来声明操作的接口(interface会更好)
public abstract class Command { protected Receiver receiver; public Command(Receiver receiver){ this.receiver = receiver; } abstract public void Execute(); }
2)具体命令类,将一个接受者绑定于一个动作,调用接受者相应的操作,以实现Execute(一系列操作)
class ConcreteCommand extends Command{ public ConcreteCommand(Receiver receiver){ super(receiver); } @Override public void Execute(){ receiver.Action(); } }
3)传达者,要求该命令执行这个或一系列请求
class Invoker{ private Command command; // private List<Command> l = new ArrayList<>(); public void setCommand(Command command){ this.command = command; } public void ExecuteCommand(){ command.Execute(); } }
4)接收者,知道如何实施与执行一个与请求相关的操作
class Receiver{ public void Action(){ /*执行请求*/ System.out.println("执行请求!"); } }
5)命令接受及执行过程
public class Test { public static void main(String[] args) { Receiver r = new Receiver(); Command c = new ConcreteCommand(r); Invoker i = new Invoker(); i.setCommand(c); i.ExecuteCommand(); } }
命令模式的要点:
I. 命令模式将发出请求的对象和执行请求的对象解耦。
II. 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。
III. 调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用(命令可以支持撤销)。
IV. 宏命令是命令的一种延伸,允许调用多个命令。
V. 命令也可以用来实现日志和事务系统。
3. BBQ烧烤档
1)烧烤店厨师:执行烧烤命令的类/*烧烤者,能执行命令的人*/ class Barbecuer{ public void BakeMutton(){ /*烤羊肉串*/ System.out.println("烤羊肉串"); } public void BakeChickenWing(){ /*烤鸡翅*/ System.out.println("烤鸡翅"); } public void BakeBacon(){ /*烤培根*/ System.out.println("烤培根"); } }
2)抽象命令类,关于烧烤的命令
//抽象命令 interface BBQCommand{ //执行命令 abstract public void excuteCommand(); @Override public String toString(); }
3)具体命令类,执行命令时,执行具体的行为,烤不同的食材。(如烤鸡翅)
/*具体命令类。执行命令时,执行具体的行为*/ class BakeMuttonCommand implements BBQCommand{ //烤羊肉串命令 Barbecuer barbecuer; public BakeMuttonCommand(Barbecuer barbecuer) { this.barbecuer = barbecuer; } @Override public void excuteCommand() { barbecuer.BakeMutton(); } @Override public String toString() { return this.getClass().getName(); } } class BakeChickenWingCommand implements BBQCommand{ //烤鸡翅命令 Barbecuer barbecuer; public BakeChickenWingCommand(Barbecuer barbecuer) { this.barbecuer = barbecuer; } @Override public void excuteCommand() { barbecuer.BakeChickenWing(); } @Override public String toString() { return this.getClass().getName(); } } class BakeBaconCommand implements BBQCommand{ //烤培根命令 Barbecuer barbecuer; public BakeBaconCommand(Barbecuer barbecuer) { this.barbecuer = barbecuer; } @Override public void excuteCommand() { barbecuer.BakeBacon(); } @Override public String toString() { return this.getClass().getName(); } }
4)具体命令类,宏命令。执行此命令时,会执行一系列命令。
//宏命令。(来个烧烤套餐) class MacroCommand implements BBQCommand{ BBQCommand[] commands; public MacroCommand(BBQCommand[] commands){ this.commands = commands; } @Override public void excuteCommand() { for(BBQCommand c:commands){ c.excuteCommand(); } } @Override public String toString() { return this.getClass().getName(); } }
5)传递者类,传达请求,与请求者及执行者都解耦了。此处即为服务员。
/*服务员。传递命令的类*/ class Waiter{ private List<BBQCommand> orders = new ArrayList<>(); //存放命令的容器 //设置订单 public void setOrder(BBQCommand command){ if(command.toString() == "Command.BakeChickenWingCommand"){ //货存确认 System.out.println("无存货:" + command.toString()); }else{ orders.add(command); System.out.println("增加订单:" + command.toString()); } } //取消订单 public void cancelOrder(BBQCommand command){ orders.remove(command); System.out.println("取消订单:" + command); } //通知全部执行 public void notifyExecuter(){ for(BBQCommand c:orders){ c.excuteCommand(); } } }
6)客户端,即完成命令模式的系统或插件。此处为烧烤店。
public class BBQ { public static void main(String[] args) { //开店前的准备 Barbecuer boy = new Barbecuer(); BBQCommand a = new BakeMuttonCommand(boy); BBQCommand b = new BakeChickenWingCommand(boy); BBQCommand c = new BakeBaconCommand(boy); BBQCommand[] SetMeal = {a,b,c}; BBQCommand d = new MacroCommand(SetMeal); //烧烤套餐 Waiter girl = new Waiter(); //开店营业 顾客点菜 girl.setOrder(a); girl.setOrder(b); girl.setOrder(c); girl.setOrder(d); girl.setOrder(a); girl.cancelOrder(a); //撤销命令 //点菜完毕,通知厨房 girl.notifyExecuter(); } }
7)运行结果,当命令类名为烤鸡翅时,显示无存货。(实际应用时可在客户端,即烧烤店里记录存货以对比库存)
4. 总结
1)命令模式较为容易地设计一个命令队列;2)能将命令记入日志,并以此来支持撤销功能;
3)加入新的具体命令类不影响其他的类,因此增加新的命令类很容易;
4)封装方法调用中的五点要点。
注意:
敏捷开发原则告诉我们,不要为代码添加基于猜测的、实际不需要的功能。如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。(自大话设计模式)
参考资料:
1.《Head First设计模式》
2.《大话设计模式》
相关文章推荐
- java集合整理
- 01背包问题-java
- LinearLayout 属性详解
- Java中选择排序的代码实现
- Java编程风格与命名规范整理
- Java之心跳机制
- Java中的内部类
- RelativeLayout常用属性介绍
- spring二次代理的问题
- 编程之美2.41的数目Java版
- Java千百问_08JDK详解(003)_jdk基础类库都有什么
- leetcode 147. Insertion Sort List-链表插入排序
- 冒泡排序的Java实现代码
- HBase的JavaAPI操作
- java7 新特性 Files copy
- Spring+Spring mvc+Mybatis整合教程
- 怎么让eclipse控制器打印全部信息
- eclipse 基础设置
- Java实现mysql存储过程调用
- Java的JAR包, EAR包 ,WAR包内部结构