首页 > 代码库 > 设计模式——命令模式
设计模式——命令模式
命令模式定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
首先我们的集中点在“命令”两个字身上。命令的汉语解释为:命令(令)是国家行政机关及其领导人发布的指挥性和强制性的公文。说白了命令的发生需要发令者和执行者。而且发令者和执行者各司其职,发令者只负责发令,甚至他自己都可以不知道这条命令具体该如何执行,而执行者只负责执行这条命令,他不需要知道如何发令,很多时候他也没有资格去发令。
以简单的"电脑开机"来举例说明:人扮演的是发令者的角色,而电脑上的开机组件扮演的是命令执行者角色。人不需要去知道开机这条命令在电脑内部具体如何执行,只需要知道按一下开机键即可,具体的开机操作由电脑开机组件去完成,这样就达到了发令者和执行者之间解耦的效果。人知道如何发令之后,可以通过"按一下按键"这一操作来执行很多操作,比如开启电视,开启车门,切换空调模式等等,人只需要知道"按一下键"来发号施令,而具体的操作由相应的命令接收者来完成。
下面以"电脑开机"来详细说明什么是命令模式:
命令模式中涉及到几个通用的类:Command, ConcreteCommand, Client, Invoker, Receiver。具体的名字可以由用户根据自己的习惯而定,如果联系到"电脑开机"这一实际操作,那么这几个类的映射关系如下:
- Command -----> 命令的通用接口
- ConcreteCommand -----> 开机命令
- Client -----> 用户
- Invoker -----> 开机键与开机组件之间的线路
- Receiver -----> 开机组件
下面我们来具体编程实现(UML图如下):
1 先定义一个通用命令接口: 2 /** 3 * 命令接口 4 * @author Apache_xiaochao 5 * 6 */ 7 public abstract class Command { 8 9 protected Receiver receiver; //命令接收者10 11 /**12 * 设置命令的接收者13 * @param receiver14 */15 public Command(Receiver receiver) {16 super();17 this.receiver = receiver;18 }19 20 /**21 * 命令执行函数22 */23 public abstract void execute();24 }
1 定义具体的开机命令(这里使用了通用类名,实际中可以替换成更加直观的类名): 2 /** 3 * 具体的命令 4 * @author Apache_xiaochao 5 * 6 */ 7 public class ConcreteCommand extends Command { 8 9 /**10 * 设置命令的接收者11 * @param receiver12 */13 public ConcreteCommand(Receiver receiver) {14 super(receiver);15 // TODO Auto-generated constructor stub16 }17 18 @Override19 public void execute() {20 //命令的主体 ,命令本身不去执行具体的操作,而是给命令的接收者一个通知,具体操作由命令的接收者去做21 receiver.doSomething();22 }23 24 }
1 定义开机组件(这里使用了通用类名,实际中可以替换成更加直观的类名): 2 /** 3 * 这是一个命令接收者,负责执行命令 4 * @author Apache_xiaochao 5 * 6 */ 7 public class Receiver { 8 9 /**10 * 开机函数11 */12 public void doSomething(){13 System.out.println("命令接收者:Windows 正在启动...");14 }15 }
1 定义用户类: 2 /** 3 * 客户类,创建一个命令,并设置命令的接收者 4 * @author Apache_xiaochao 5 * 6 */ 7 public class Client { 8 9 /**10 * 创建一个命令,并设置命令的接收者11 */12 public Command createCommand(){13 Receiver receiver = new Receiver();14 //创建一条命令,并指定命令的接收者15 Command command = new ConcreteCommand(receiver);16 return command;17 }18 }
1 定义开机键与开机组件之间的线路(这里使用了通用类名,实际中可以替换成更加直观的类名): 2 /** 3 * 命令传递类 4 * @author Apache_xiaochao 5 * 6 */ 7 public class Invoker { 8 9 private Command command;10 11 /**12 * 通知命令接收者执行命令13 */14 public void notifyReceiver(){15 command.execute();16 }17 /**18 * 获取命令19 * @param command20 */21 public void setCommand(Command command) {22 this.command = command;23 }24 }
1 public class Driver { 2 public static void main(String[] args) { 3 //用户按下开机键 4 Client client = new Client(); 5 Command command = client.createCommand(); //客户端创建一条命令 6 //通信线路传递命令 7 Invoker invoker = new Invoker(); 8 invoker.setCommand(command); //获取用户创建的命令 9 invoker.notifyReceiver(); //传递命令,通知开机组件,有人要开机10 }11 }
整个程序的大致流程为:
- Client创建命令,并指定命令的接收者
- Invoker传递命令,通知命令接收者执行命令
- Receiver接收命令,解析并执行
这里的命令都是指单一的命令,当用户按下开机键的时候,当然也可以触发一系列操作,比如开机的同时弹出光驱等(只是举例,实际中这肯定是不可取的),称之为宏命令。
当然我们还可以在命令模式中定义撤销的功能(比如误按了开机键,想取消开机),思路都是记录前一次或者几次的操作,然后执行相应的反操作来完成的。
总结:
- 命令模式将发出命令的对象和执行命令对象之间解耦
- 发令者和执行者之间通过命令对象进行沟通,命令对象封装了命令接收者,以及一个或一组动作
- 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行之前的状态
- 宏命令是命令的一种简单延伸,允许调用多个命令,支持撤销
- 命令也可以用来实现日志和事务系统
设计模式——命令模式
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。