本文出自   http://blog.csdn.net/shuangde800

走进命令模式

在餐厅的情境中,我们看看餐厅是怎样工作的:

1、顾客走进餐厅,点好菜后,生成订单交给女服务员

2、女服务员订单拿到厨房工作室,大喊一声:“订单来了!”

3、厨师订单准备餐点。

上面情境各角色职责:

1、订单封装了顾客的请求。 和一般的对象一样,订单可以被传递,订单内包含一个方法 orderUp(), 这个方法封装了准备餐点所需的动作。订单内有厨师的引用。这些都被封装起来。

2、女服务员的工作就是接受订单,然后调用订单的orderUp( )方法。这里的orderUp具体内容就是把订单交给厨师。

女服务员不必知道订单的内容是什么,只需要知道订单中有一个orderUp( )的方法可以调用就够了。

3、厨师具备准备餐点的知识

厨师是一种对象,他真正知道如何准备餐点。一旦女服务员调用orderUp( )方法,厨师就接手马上做好餐点。

女服务员和厨师之间的关系是彻底解耦的,请注意,女服务员的订单封装了餐点的细节,她只要调用订单的方法即可,而厨师看了订单就知道该做什么餐点,厨师和女服务员之间从来不用直接沟通。

从餐厅到命令模式

把餐厅想象成OO设计模式中的一种模型,这个模型允许将“发出的请求的对象”和“接受与执行这些请求的对象”分隔开来。

比方说,对于遥控器的例子:

有一个遥控器

上面有不同功能的卡槽,旁边对应卡槽的开关按钮,遥控器厂商提供了相关卡槽功能的类。如何设计这个遥控器的API?

对于遥控器API,我们需要分隔开“发出请求的的按钮代码”和执行请求的"厂商特定对象"。

假设遥控器插槽上有一个餐厅订单的对象,那么按按钮,就会调用该对象的orderUp()方法,然后就可以等待大餐上来了!

命令模式可以将“动作的请求者”从动作的执行者对象中解耦。上面遥控器是请求者,而执行者对象就是厂商类的其中之一的实例。

利用命令模式把遥控器每个键的请求封装成一个特定对象,所以,每个按钮都存储一个命令对象,那么当按下按钮时,就可以请命令对象做相关的工作。遥控器并不需要知道工作内容是什么,只要有这个命令对象就能和正确的对象沟通,把事情做好就可以了。

第一个命令对象

下面用命令模式实现遥控器的代码
1. 实现命令接口
// 命令接口,所有的命令对象实现这个接口
public interface Command {// 简单! 只需要一个方法:execute()public void execute();
}

2. 实现一个打开电灯的命令

// 实现一个打开电灯的命令
// 要实现Command的接口
public class LightOnCommand implements Command{Light light;// light是接收者public LightOnCommand(Light light) {this.light = light; }// 执行接收者的动作public void execute() {light.on(); }
}

3. 使用命令对象


下面是调用者

public class SimpleRemoteControl{// 有一个插槽持有命令,而这个命令控制着一个装置Command slot; public SimpleRemoteControl() { }// 这个方法用来设置插槽控制的命令。// 如果这段代码的客户想要改变public void setCommand(Command command) {slot = command; }// 当按下按钮时,这个方法就会被调用// 使得当前命令衔接插槽,并调用他的execute()方法public void buttonWasPressed() {slot.execute();}
}

4. 遥控器使用的简单测试

下面代码,用来测试上面的简单遥控器

public class RemoteControlTest {//这是命令模式的客户public static void main(String[] args) {// 遥控器就是调用者,会传入一个命令对象,可以用来发出请求SimpleRemoteControl remote = new SimpleRemoteControl();// 创建一个电灯对象,此对象是接收者Light light = new Light();// 这里创建一个命令,然后接收者传给他LightOnCommand lightOn = new LightOnCommand(light);// 把命令传给调用者remote.setCommand(lightOn);// 模拟按下按钮remote.buttonWasPressed();}
}

定义命令模式

命令模式将“请求”封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象。命令模式也支持可撤销的操作

1.命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。

2.每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作。

3.命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

4.命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。

5.命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

撤销命令模式

要在遥控器加上撤销功能很简单,它的功能是这样的:比如说是电灯关闭的,你按下了开启按钮,电灯就亮了,然后你按下撤销按钮,灯就又不亮了。相当与撤销上一次的命令。

1. 在Command接口上加上undo()方法

public interface Command {public void execute();public void undo();
}

2. 如果是开灯的命令,那么他的撤销命令就是关灯。同理,如果是关灯的命令,那么他的撤销命令就是开灯。

// 开灯命令
public class LightOnCommand implements Command{Light light;public LightOnCommand(Light light) {this.light = light; }public void execute() {light.on(); }// 实现了撤销功能:变成关灯public void undo(){light.off();}
}
// 关灯命令
public class LightOffCommand implements Command{Light light;public LightOffCommand(Light light) {this.light = light; }public void execute() {light.off(); }// 关灯的撤销命令是开灯public void undo(){light.on();}
}

要实现命令模式的撤销功能,还是很简单的,只要学会了保存上一次的命令,那么随便就可以写出来了

宏命令模式

如果遥控器拥有一个功能,按下一个按钮,就可以实现很多功能,要怎么做?

也很简单,用一个数组存下所有命令即可

public class MacroCommand implements Command {Command[] commands;public MacroCommand(Command[] commands) {this.commands = commands; }public void execute() {for(int i = 0; i < commands.length; i++)commands[i].execute();}public void undo() {for(int i = 0; i < commands.length; ++i)commands[i].undo();}
}

如果要可以撤销很多次怎么做?

也很简单,不只是记录最后一个被执行的命令,而使用一个堆栈记录操作过程的没一个命令。然后不管什么时候按下了撤销按钮,你都可以从堆栈中取出最上层的命令,然后调用它的undo()方法。

命令模式的更多用途: 队列请求

命令可以将运算块打包,然后把它传来传去,就像是一般的对象一样。即使命令对象被创建许久之后,运算依然可以被调用。

事实上,它甚至可以在不同的线程中被调用。我们利用这样的特性衍生出一些应用,例如:日程安排(Scheduler),线程池,工作队列等。

命令模式的更多用途:日志请求

某些应用需要把所有动作都记录在日志中,并能在系统死机后,重新调用这些动作恢复到之前的状态。

通过新增两个方法(store(), load() ),命令模式就能够支持这一点。

在只要当我们执行命令时,将历史记录存储在磁盘中,一旦系统死机,就可以将命令对象重载,并成批地一次调用这些

对象的execute()方法。

转载于:https://www.cnblogs.com/bbsno1/p/3253672.html

【设计模式】学习笔记8:命令模式相关推荐

  1. 【转】设计模式学习笔记之命令模式

    定义:将请求封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式支持可撤销等操作. 命令模式将发出请求的对象和执行请求的对象解耦.在被解耦的两者之间是通过命令对象进行沟通的. 案例代 ...

  2. 设计模式学习笔记——解释器(Interpreter)模式

    设计模式学习笔记--解释器(Interpreter)模式 @(设计模式)[设计模式, 解释器模式, Interpreter] 设计模式学习笔记解释器Interpreter模式 基本介绍 解释器案例 类 ...

  3. 设计模式学习笔记——代理(Proxy)模式

    设计模式学习笔记--代理(Proxy)模式 @(设计模式)[设计模式, 代理模式, proxy] 设计模式学习笔记代理Proxy模式 基本介绍 代理案例 类图 实现代码 Printable接口 Pri ...

  4. 设计模式学习笔记——状态(State)模式框架

    设计模式学习笔记--状态(State)模式框架 @(设计模式)[设计模式, 状态模式, State] 设计模式学习笔记状态State模式框架 基本介绍 状态案例 类图 实现代码 State接口 Day ...

  5. 设计模式学习笔记——备忘录(Memento)模式

    设计模式学习笔记--备忘录(Memento)模式 @(设计模式)[设计模式, 备忘录模式, memento] 设计模式学习笔记备忘录Memento模式 基本介绍 备忘录案例 类图 实现代码 Memen ...

  6. 设计模式学习笔记——观察者(Observer)模式

    设计模式学习笔记--观察者(Observer)模式 @(设计模式)[设计模式, 观察者模式, Observer] 设计模式学习笔记观察者Observer模式 基本介绍 观察者案例 类图 实现代码 Ob ...

  7. 设计模式学习笔记——外观(Facade)模式

    设计模式学习笔记--外观(Facade)模式 @(设计模式)[设计模式, 外观模式, facade] 设计模式学习笔记外观Facade模式 基本介绍 外观案例 类图 实现代码 Database类 ma ...

  8. 设计模式学习笔记——访问者(Visitor)模式

    设计模式学习笔记--访问者(Visitor)模式 @(设计模式)[设计模式, 访问者模式, visitor] 设计模式学习笔记访问者Visitor模式 基本介绍 访问者案例 类图 实现代码 Visit ...

  9. 设计模式学习笔记——装饰(Decorator)模式

    设计模式学习笔记--装饰(Decorator)模式 @(设计模式)[设计模式, 装饰模式, decorator] 设计模式学习笔记装饰Decorator模式 基本介绍 装饰案例 类图 实现代码 Dis ...

  10. 设计模式学习笔记——组合(Composite)模式

    设计模式学习笔记--组合(Composite)模式 @(设计模式)[设计模式, 组合模式, composite] 设计模式学习笔记组合Composite模式 基本介绍 组合案例 类图 实现代码 Ent ...

最新文章

  1. Tomcat 1099端口占用重启无效,查不到进程,改换端口无效解决方案
  2. 液晶显示屏怎么显示泰文_液晶显示屏概念股大涨 液晶显示屏概念股一览表
  3. 【机器学习算法-python实现】逻辑回归的实现(LogicalRegression)
  4. git查看相对于最新的push改动内容
  5. pl sql 工具insert into 中文 后, select为乱码
  6. windows7如何实现屏幕不休眠
  7. server sql top速度变慢解决方案_SQL Server的性能调优:解决查询速度慢的五种方法-数据库...
  8. 佳博ip修改工具_如何修改设备IP,换IP来组建网络
  9. poj3660 Cow Contest
  10. 【二分】【线段树】hdu6070 Dirt Ratio
  11. React Suite 组件库
  12. 程序员电脑屏保画面,显示时间
  13. 支持向量机(SVM)理解以及在sklearn库中的简单应用
  14. 华为服务器串口修改密码,huawei恢复Console口密码
  15. 《2040大预言:高科技引擎与社会新秩序》——第2章 数字化概览2.1 一生中永不停息的视频日记...
  16. 短视频批量伪原创 视频md5修改手机版
  17. 【经典算法】冒泡排序
  18. 无脑三子棋(小游戏可以这样简单)
  19. php emoji表情,PHP处理字符中的emoji表情
  20. 实施工程师或技术支持必须熟悉的技能

热门文章

  1. 不同林间域账号密码迁移
  2. 利用U盘安装windows 7
  3. SQLServer 优化SQL语句:in 和not in的替代方案
  4. Java程序停止 mq通道未关闭_java – 如何在MQ上停止丢失消息
  5. activiti利弊_事件驱动的安全性的利弊
  6. (14)css—伪类选择器
  7. 财政 | 十一月财政总结
  8. es6 Trait修饰器
  9. heap c语言数组实现,垃圾回收算法实现之 - 分代回收(完整可运行C语言代码)...
  10. Linux Ubuntu下Jupyter Notebook的安装