文档章节

《设计模式》之命令模式

h
 haidao1992
发布于 2017/06/24 19:59
字数 1603
阅读 3
收藏 0

一、命令模式定义

命令大家都不会陌生,那么在开始命令模式之前,可以想象一下生活中的命令模式的特点:

如老板命令你完成一个OA项目是一个命令,接着看看其特点:

1、在上面的命令中,命令的执行者肯定是聪明的你了。具体的执行方法,可能是通过vs实现,或者是通过eclipse实现,由此看来:命令要有个命令的执行者,还要有个命令的执行方法。

2、命令的发出者很明显是老板,老板还有个发出方法,可能是通过电话给你说,也可能给你邮件给你说,也可能是通过开会给你说。所以命令的发出者要有一个命令,还要有个发出的方法。

3、最后看看命令,命令有个名字,命令的肯定要执行。而且命令是在boss给你发出通知后执行的。

接下来看看命令模式的定义:

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

二、问题描述

 

     使用命令模式实现遥控器,遥控器上的不同按钮控制电灯的开关及亮度、天花板风扇的开关及转速等,支持撤销。具体按钮:开灯/关灯按钮、暗光开/关按钮、风扇高速/中速/低速/关按钮、撤销按钮。遥控器如下图所示:

     遥控器担当请求者(或称为调用者)的角色,用RemoteControlWithUndo类实现,其内有Command[]类型的属性onCommands和offCommands表示对应的一组开关,Command类型的属性undoCommand记录最后执行的命令用于命令的撤销。遥控器上有7组开关按钮和一个撤销按钮。每个按钮对应一个具体命令,说明如下:

三、类图

四、代码实现

1.命令角色:Command

  1. public interface Command {  
  2.     public void execute();  
  3.     public void undo();//实现撤销  
  4. }  

2.接收者角色:Light、CeilingFan

(1)Light电灯:

  1. public class Light {  
  2.     String location;  
  3.     int level;//灯光的亮度  
  4.   
  5.     public Light(String location) {  
  6.         this.location = location;  
  7.     }  
  8.   
  9.     public void on() {  
  10.         level = 100;  
  11.         System.out.println("Light is on");  
  12.     }  
  13.   
  14.     public void off() {  
  15.         level = 0;  
  16.         System.out.println("Light is off");  
  17.     }  
  18.     //调整灯光的亮度  
  19.     public void dim(int level) {  
  20.         this.level = level;  
  21.         if (level == 0) {  
  22.             off();  
  23.         }  
  24.         else {  
  25.             System.out.println("Light is dimmed to " + level + "%");  
  26.         }  
  27.     }  
  28.    //获取灯光的亮度  
  29.     public int getLevel() {  
  30.         return level;  
  31.     }  
  32. }  

(2)CeilingFan风扇:

  1. public class CeilingFan {  
  2.     public static final int HIGH = 3;  
  3.     public static final int MEDIUM = 2;  
  4.     public static final int LOW = 1;  
  5.     public static final int OFF = 0;  
  6.     String location;//例如卧室、客厅的风扇?  
  7.     int speed;  
  8.    
  9.     public CeilingFan(String location) {  
  10.         this.location = location;  
  11.         speed = OFF;  
  12.     }  
  13.     
  14.     public void high() {  
  15.         speed = HIGH;  
  16.         System.out.println(location + " ceiling fan is on high");  
  17.     }   
  18.    
  19.     public void medium() {  
  20.         speed = MEDIUM;  
  21.         System.out.println(location + " ceiling fan is on medium");  
  22.     }  
  23.    
  24.     public void low() {  
  25.         speed = LOW;  
  26.         System.out.println(location + " ceiling fan is on low");  
  27.     }  
  28.     
  29.     public void off() {  
  30.         speed = OFF;  
  31.         System.out.println(location + " ceiling fan is off");  
  32.     }  
  33.     
  34.     public int getSpeed() {  
  35.         return speed;  
  36.     }  
  37. }  

3.具体命令角色:各种命令

(1)NoCommand:空命令,创建遥控器时默认其持有的都是空命令(相比判断null更好),什么事也不做

  1. public class NoCommand implements Command {  
  2.     public void execute() { }  
  3.     public void undo() { }  
  4. }  

(2)LightOnCommand:开灯命令

  1. public class LightOnCommand implements Command {  
  2.     Light light;  
  3.     int level;//level用于记录上次的灯光亮度  
  4.     public LightOnCommand(Light light) {  
  5.         this.light = light;  
  6.     }  
  7.    
  8.     public void execute() {  
  9.         level = light.getLevel();  
  10.         light.on();  
  11.     }  
  12.    
  13.     public void undo() {//将灯光的亮度调到前一次的水平实现撤销  
  14.         light.dim(level);  
  15.     }  
  16. }  


(3)LightOffCommand:关灯命令

  1. public class LightOffCommand implements Command {  
  2.     Light light;  
  3.     int level;  
  4.     public LightOffCommand(Light light) {  
  5.         this.light = light;  
  6.     }  
  7.    
  8.     public void execute() {  
  9.         level = light.getLevel();  
  10.         light.off();  
  11.     }  
  12.    
  13.     public void undo() {  
  14.         light.dim(level);  
  15.     }  
  16. }  


(4)DimmerLightOnCommand:开启暗光

  1. public class DimmerLightOnCommand implements Command {  
  2.     Light light;  
  3.     int prevLevel;//记录以前的灯光亮度,撤销操作时使用  
  4.   
  5.     public DimmerLightOnCommand(Light light) {  
  6.         this.light = light;  
  7.     }  
  8.   
  9.     public void execute() {  
  10.         prevLevel = light.getLevel();  
  11.         light.dim(75);//将灯光亮度调至75%实现暗光  
  12.     }  
  13.   
  14.     public void undo() {  
  15.         light.dim(prevLevel);  
  16.     }  
  17. }  


(5)DimmerLightOffCommand:关闭暗光

  1. public class DimmerLightOffCommand implements Command {  
  2.     Light light;  
  3.     int prevLevel;  
  4.   
  5.     public DimmerLightOffCommand(Light light) {  
  6.         this.light = light;  
  7.         prevLevel = 100;  
  8.     }  
  9.   
  10.     public void execute() {  
  11.         prevLevel = light.getLevel();  
  12.         light.off();  
  13.     }  
  14.   
  15.     public void undo() {  
  16.         light.dim(prevLevel);  
  17.     }  
  18. }  

(6)CeilingFanHighCommand:风扇高转速

  1. public class CeilingFanHighCommand implements Command {  
  2.     CeilingFan ceilingFan;  
  3.     int prevSpeed;//记录以前的转速,用于撤销操作(0时表示以前的状态是:关)  
  4.     
  5.     public CeilingFanHighCommand(CeilingFan ceilingFan) {  
  6.         this.ceilingFan = ceilingFan;  
  7.     }  
  8.    
  9.     public void execute() {  
  10.         prevSpeed = ceilingFan.getSpeed();  
  11.         ceilingFan.high();  
  12.     }  
  13.    
  14.     public void undo() {  
  15.         if (prevSpeed == CeilingFan.HIGH) {  
  16.             ceilingFan.high();  
  17.         } else if (prevSpeed == CeilingFan.MEDIUM) {  
  18.             ceilingFan.medium();  
  19.         } else if (prevSpeed == CeilingFan.LOW) {  
  20.             ceilingFan.low();  
  21.         } else if (prevSpeed == CeilingFan.OFF) {  
  22.             ceilingFan.off();  
  23.         }  
  24.     }  
  25. }  

(7)CeilingFanMediumCommand:风扇中转速

  1. public class CeilingFanMediumCommand implements Command {  
  2.     CeilingFan ceilingFan;  
  3.     int prevSpeed;  
  4.     
  5.     public CeilingFanMediumCommand(CeilingFan ceilingFan) {  
  6.         this.ceilingFan = ceilingFan;  
  7.     }  
  8.    
  9.     public void execute() {  
  10.         prevSpeed = ceilingFan.getSpeed();  
  11.         ceilingFan.medium();//将行为的真正执行委托给接收者,此处即ceilingFan风扇对象  
  12.     }  
  13.    
  14.     public void undo() {  
  15.         if (prevSpeed == CeilingFan.HIGH) {  
  16.             ceilingFan.high();  
  17.         } else if (prevSpeed == CeilingFan.MEDIUM) {  
  18.             ceilingFan.medium();  
  19.         } else if (prevSpeed == CeilingFan.LOW) {  
  20.             ceilingFan.low();  
  21.         } else if (prevSpeed == CeilingFan.OFF) {  
  22.             ceilingFan.off();  
  23.         }  
  24.     }  
  25. }  

(8)CeilingFanLowCommand:风扇低转速

  1. public class CeilingFanLowCommand implements Command {  
  2.     CeilingFan ceilingFan;  
  3.     int prevSpeed;  
  4.     
  5.     public CeilingFanLowCommand(CeilingFan ceilingFan) {  
  6.         this.ceilingFan = ceilingFan;  
  7.     }  
  8.    
  9.     public void execute() {  
  10.         prevSpeed = ceilingFan.getSpeed();  
  11.         ceilingFan.low();  
  12.     }  
  13.    
  14.     public void undo() {  
  15.         if (prevSpeed == CeilingFan.HIGH) {  
  16.             ceilingFan.high();  
  17.         } else if (prevSpeed == CeilingFan.MEDIUM) {  
  18.             ceilingFan.medium();  
  19.         } else if (prevSpeed == CeilingFan.LOW) {  
  20.             ceilingFan.low();  
  21.         } else if (prevSpeed == CeilingFan.OFF) {  
  22.             ceilingFan.off();  
  23.         }  
  24.     }  
  25. }  

(9)CeilingFanOffCommand:关闭风扇

  1. public class CeilingFanOffCommand implements Command {  
  2.     CeilingFan ceilingFan;  
  3.     int prevSpeed;  
  4.     
  5.     public CeilingFanOffCommand(CeilingFan ceilingFan) {  
  6.         this.ceilingFan = ceilingFan;  
  7.     }  
  8.    
  9.     public void execute() {  
  10.         prevSpeed = ceilingFan.getSpeed();  
  11.         ceilingFan.off();  
  12.     }  
  13.    
  14.     public void undo() {  
  15.         if (prevSpeed == CeilingFan.HIGH) {  
  16.             ceilingFan.high();  
  17.         } else if (prevSpeed == CeilingFan.MEDIUM) {  
  18.             ceilingFan.medium();  
  19.         } else if (prevSpeed == CeilingFan.LOW) {  
  20.             ceilingFan.low();  
  21.         } else if (prevSpeed == CeilingFan.OFF) {  
  22.             ceilingFan.off();  
  23.         }  
  24.     }  
  25. }  

4.遥控器类,请求者(或调用者)角色,持有多个Command对象

  1. public class RemoteControlWithUndo {  
  2.     Command[] onCommands;//对应多个开按钮  
  3.     Command[] offCommands;//对应多个关按钮  
  4.     Command undoCommand;//对应撤销按钮  
  5.    
  6.     public RemoteControlWithUndo() {  
  7.         onCommands = new Command[7];  
  8.         offCommands = new Command[7];  
  9.    
  10.         Command noCommand = new NoCommand();  
  11.         for(int i=0;i<7;i++) {  
  12.             onCommands[i] = noCommand;//默认赋值为空命令,什么事也不做  
  13.             offCommands[i] = noCommand;  
  14.         }  
  15.         undoCommand = noCommand;  
  16.     }  
  17.     
  18.     public void setCommand(int slot, Command onCommand, Command offCommand) { 
  19.         onCommands[slot] = onCommand;  
  20.         offCommands[slot] = offCommand;  
  21.     }  
  22.    
  23.     //当编号为第slot的开On按钮按下时执行命令  
  24.     public void onButtonWasPushed(int slot) {  
  25.         onCommands[slot].execute();  
  26.         undoCommand = onCommands[slot];//记录最后执行的命令  
  27.     }  
  28.    
  29.     public void offButtonWasPushed(int slot) {  
  30.         offCommands[slot].execute();  
  31.         undoCommand = offCommands[slot];  
  32.     }  
  33.    
  34.     public void undoButtonWasPushed() {  
  35.         undoCommand.undo();  
  36.     }  
  37.     
  38.     public String toString() {  
  39.         StringBuffer stringBuff = new StringBuffer();  
  40.         stringBuff.append("\n------ Remote Control -------\n");  
  41.         for (int i = 0; i < onCommands.length; i++) {  
  42.             stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()  
  43.                 + "    " + offCommands[i].getClass().getName() + "\n");  
  44.         }  
  45.           
  46.         stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n");  
  47.         return stringBuff.toString();  
  48.     }  
  49. }  

5.测试

  1. public class RemoteLoader {  
  2.    
  3.     public static void main(String[] args) {  
  4.         RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();  
  5.    
  6.         Light livingRoomLight = new Light("Living Room");  
  7.    
  8.         LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);  
  9.         LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);   
  10.         DimmerLightOnCommand dimmerLightOnCommand=new DimmerLightOnCommand(livingRoomLight);  
  11.         DimmerLightOffCommand dimmerLightOffCommand=new DimmerLightOffCommand(livingRoomLight);  
  12.           
  13.         CeilingFan ceilingFan = new CeilingFan("Living Room");  
  14.      
  15.         CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);  
  16.         CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);  
  17.         CeilingFanLowCommand ceilingFanLow =new CeilingFanLowCommand(ceilingFan);  
  18.         CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);  
  19.     
  20.         remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);  
  21.         remoteControl.setCommand(1, dimmerLightOnCommand, dimmerLightOffCommand);  
  22.         remoteControl.setCommand(2, ceilingFanHigh, ceilingFanOff);  
  23.         remoteControl.setCommand(3, ceilingFanMedium, ceilingFanOff);  
  24.         remoteControl.setCommand(4, ceilingFanLow, ceilingFanOff);  
  25.   
  26.         remoteControl.onButtonWasPushed(1);  
  27.         remoteControl.onButtonWasPushed(3);  
  28.         remoteControl.onButtonWasPushed(2);  
  29.         remoteControl.offButtonWasPushed(3);  
  30.           
  31.         remoteControl.undoButtonWasPushed();  
  32.     }  
  33. }  


运行结果:

  1. Light is dimmed to 75%  
  2. Living Room ceiling fan is on medium  
  3. Living Room ceiling fan is on high  
  4. Living Room ceiling fan is off  
  5. Living Room ceiling fan is on high  

我们可以很轻松地利用组合模式加入宏命令,还有,正如以上代码所示,命令模式的不足之处就是我们需要维护大量的具体命令类。

© 著作权归作者所有

共有 人打赏支持
h
粉丝 1
博文 25
码字总数 26036
作品 0
浦东
程序员
私信 提问
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
06/24
0
0
设计模式已经陨落了?

你现在是坐在一个程序员旁边吗?如果是的话,那么在你读下面的段落之前,有一个简单的实验。让他们到一边去,问问他们两个问题并记录下答案。首先问他们“什么是设计模式?”然后再问“说出你...

oschina
2014/03/11
9.1K
69
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
11/06
0
0
设计模式梳理(一)

设计模式梳理(一) 总体来说设计模式分为三大类: @案例源码地址:https://gitlab.com/lxqxsyu/DisgnPattern 创建型模式 简单工厂模式 工厂类是整个模式的关键。它包含必要的判断逻辑,能够...

lxq_xsyu
2017/11/02
0
0
Ubuntu中vi卸载与安装/使用模式

Ubuntu中安装的vi是vim-common版本,与centos系统中vi使用方式不同,编辑使用不惯, 遂卸载重装,卸载命令:sudo apt-get remove vim-common 卸载完毕后重新安装;输入命令:sudo apt-get in...

唐十三郎
11/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

新手也能看懂,消息队列其实很简单

该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 16k)。地址:https://github.com/Snailclimb/JavaGuide. 本文内容思维导图: 消息...

阿里云官方博客
19分钟前
1
0
如何在Chrome浏览器中启动deviceready事件(尝试调试phonegap项目)?

我正在开发PhoneGap应用程序,我希望能够在Chrome中调试它,而不是在电话上调试。但是,我在onGetReady()函数中初始化我的代码,该函数在PhoneGap触发“deviceready”事件时触发。由于Chr...

kisshua
今天
9
0
nginx中部署vue打包后的静态文件

如何在nginx中部署静态资源就不描述了, 请看我的这篇博客 将vue脚手架项目打包后的静态文件放到nginx上, 发现有个问题, 即url上有#, 怎么去掉这个#呢. 1 项目中router的mode 路由的mode要为h...

克虏伯
今天
13
0
JS容易理解错误的地方

在这端代码执行的末尾,你会不会hi变量回事函数中的hi了?你会不会认为这不是按引用传递了? 对值传递和引用传递产生质疑了? 1 var hi = {};2 function sayHello(hi) { ...

器石_
今天
9
0
Java开发学习--MongoDB

之前只学过sql,第一次使用非关系型数据库。以前对于关系型数据库与非关系型数据库的概念很模糊,通过这次的学习对这两者有了一个清晰的概念。 主键 在MongoDB中,主键名叫"_id",如果在生成...

微笑向暖wx
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部