命令模式

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

类图:

 

要点:

命令模式将发出的请求对象和执行的请求对象解耦。在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接受者一个或一组请求。

调用者通过调用命令对象的excute()发出请求。这会使得接受者的命令被调用。

调用者可以接受命令做参数。甚至在运行时动态的进行。

命令可以支持撤销。做法是实现一个undo()方法来回倒execute()被执行前的状态。

命令也可以用来实现日志和事务系统。

例子:

一、问题描述

 

使用命令模式实现遥控器,遥控器上的不同按钮控制电灯的开关及亮度、天花板风扇的开关及转速等,支持撤销。

具体按钮:开灯/关灯按钮、暗光开/关按钮、风扇高速/中速/低速/关按钮、撤销按钮。

遥控器如下图所示:

遥控器担当请求者(或称为调用者)的角色,用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更好),什么事也不做

 

[java] view plaincopy
 
  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.     }  
posted @ 2016-01-22 10:34  戎码一生  阅读(314)  评论(0编辑  收藏  举报