《设计模式》之命令模式
《设计模式》之命令模式
haidao1992 发表于5个月前
《设计模式》之命令模式
  • 发表于 5个月前
  • 阅读 0
  • 收藏 0
  • 点赞 0
  • 评论 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  

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

标签: 命令模式
共有 人打赏支持
粉丝 0
博文 19
码字总数 26036
×
haidao1992
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: