文档章节

《设计模式》之命令模式

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
浦东
程序员
javascript 设计模式之工厂(Factory)模式

工厂模式介绍 工厂模式是一个创建型的模式,主要就是创建对象。其中工厂模式又分为简单工厂模式和抽象工厂模式。简单工厂模式是通过工厂方法确定创建 对应类型的对象。抽象工厂模式是通过子类...

hlxiong
2014/04/14
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
04/09
0
0
【设计模式笔记】(十六)- 代理模式

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

MrTrying
06/24
0
0
JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。 JavaScript 中...

牧云云
05/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

python3.6 取余运算

python中取余运算逻辑如下: 如果a 与d 是整数,d 非零,那么余数 r 满足这样的关系: a = qd + r , q 为整数,且0 ≤ |r| < |d|。 经过测试可发现,python3.6中取余运算得到的 r 是正整数;...

colinux
12分钟前
1
0
[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
3
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
3
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
1
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部