命令模式
1 使用场景
1. 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。
2. 命令需要进行各种管理逻辑。
3. 需要支持撤消\重做操作(撤销命令)。
2 角色
2.1 client
1、创建具体的命令
2、设置命令的接受者
2.2 Command
1 定义命令的统一接口
2 command为所有命令声明了一个借口,调用命令对象的excute方法,就可以让接受者进行相关的操作
3 这个接口也具备撤销的方法
2.3 ConcreteCommand
1 Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
2 具体命令会调用接受者的动作,以满足请求
2.4 invoker
1 命令的实际执行者
2 这个调用者持有一系列命令对象,并在某个时间调用命令对象的excute方法,将请求付诸实行。
2.5 Receiver
1 命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。
2 命令对象通过在特定接受者上绑定一组动作来封装一个请求
3 接受者有多个
4 接受者经常通过参数化对象来绑定到具体命令对象中
5 接受者知道如何进行必要的工作,实现这个请求,任何类都可以当接受者
6 一般情况下,一个具体命令对应一个具体的接受者
3 例子
3.1 客户向服务员点餐-服务员将菜单交给厨师,厨师烹饪各种食物
3.2 使用命令模式的一般步骤
1 第一步:初始化所有的接受者
2 第二步:创建所有的命令对象
3 第三步:调用者加载命令
4 第四步:在适当的时候让调用者执行命令
3.3 demo
package limanman; import java.util.ArrayList; import java.util.List; public class CommandTest { public static void main(String[] args) { Client.run(); } } class Client { public static void run() { /** * 第一步:初始化所有的接受者 */ Receiver1 receiver1 = new Receiver1(); Receiver2 receiver2 = new Receiver2(); /** * 第二步:创建所有的命令对象 */ Command command1 = new ConcreateCmonmand1(receiver1); Command command2 = new ConcreateCmonmand2(receiver2); /** * 第三步:调用者加载命令 */ Invoker invoker = new Invoker(); invoker.setCommand(command1); invoker.setCommand(command2); /** * 第四步:在适当的时候让调用者执行命令 */ invoker.callRecever(0); invoker.callRecever(1); } } /** * 接受者1,一个具体命令对应一个具体接收者 * * @author limanman * @date 2015年10月12日 */ class Receiver1 { public void action() { System.out.println("接收者1执行具体的操作"); } } /** * 接受者2,一个具体命令对应一个具体接收者 * * @author limanman * @date 2015年10月12日 */ class Receiver2 { public void action() { System.out.println("接收者2执行具体的操作"); } } /** * 命令角色 * * @author limanman * @date 2015年10月12日 */ interface Command { public void excute(); } /** * 角色: 具体命令 * * @author limanman * @date 2015年10月12日 */ class ConcreateCmonmand1 implements Command { Receiver1 receiver1; public ConcreateCmonmand1(Receiver1 receiver1) { this.receiver1 = receiver1; } @Override public void excute() { System.out.println("执行命令1"); receiver1.action(); } } class ConcreateCmonmand2 implements Command { Receiver2 receiver2; public ConcreateCmonmand2(Receiver2 receiver2) { this.receiver2 = receiver2; } @Override public void excute() { System.out.println("执行命令2"); receiver2.action(); } } /** * 角色:invoker * * @author limanman * @date 2015年10月12日 */ class Invoker { List<Command> commands = new ArrayList<Command>(); /** * 设置命令 * * @param command * @date 2015年10月12日 * @author 佚名 */ public void setCommand(Command command) { commands.add(command); } /** * 调用者持有一系列命令对象,并在某个时间点调用对象的excute方法,将请求付诸实行 * * @param slot * @date 2015年10月12日 * @author 佚名 */ public void callRecever(int slot) { commands.get(slot).excute(); } }
输出:
执行命令1
接受者1执行具体的操作
执行命令2
接受者2执行具体的操作
4 要点
1 命令模式是通过命令发送者和命令执行者的解耦来完成对命令的具体控制的。
2 命令模式是对功能方法的抽象,并不是对对象的抽象。
3 命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。
5 设计原则
对修改封闭,对扩展开放
6 核心
1 参数化对象,对象中包含请求和具体的操作
2 请求者创建命令和接受者,接受者执行命令和撤销命令
7 定义
"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象,命令模式也支持可撤销的操作
8 好处
1.更方便的对命令进行扩展
2.对多个命令的统一控制
3.支持撤销操作
9 问题
9.1 命令模式的设计如何支持请求者和请求接受者之间的解耦
1、invoker只是包含了抽象的命令(interface)
2、具体的命令和接受者跟invoker没有直接的关联