命令模式

《Head First设计模式》Eric Freeman;Elisabeth Freeman;Kathy Sierra;Bert Bates
中国电力出版社
ISBN:9787508353937

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

命令模式代码示例:
Command接口

 
 
  1. package net.dp.command.simpleremote; 
  2.  
  3. public interface Command { 
  4.     public void execute(); 


所要封装的两个事物GarageDoor和Light(Receiver)

 
 
  1. package net.dp.command.simpleremote; 
  2.  
  3. public class GarageDoor { 
  4.  
  5.     public GarageDoor() { 
  6.     } 
  7.  
  8.     public void up() { 
  9.         System.out.println("Garage Door is Open"); 
  10.     } 
  11.  
  12.     public void down() { 
  13.         System.out.println("Garage Door is Closed"); 
  14.     } 
  15.  
  16.     public void stop() { 
  17.         System.out.println("Garage Door is Stopped"); 
  18.     } 
  19.  
  20.     public void lightOn() { 
  21.         System.out.println("Garage light is on"); 
  22.     } 
  23.  
  24.     public void lightOff() { 
  25.         System.out.println("Garage light is off"); 
  26.     } 
  27.  
  28. package net.dp.command.simpleremote; 
  29.  
  30. public class Light { 
  31.  
  32.     public Light() { 
  33.     } 
  34.  
  35.     public void on() { 
  36.         System.out.println("Light is on"); 
  37.     } 
  38.  
  39.     public void off() { 
  40.         System.out.println("Light is off"); 
  41.     } 


封装的具体命令(ConcreteCommand)

 
 
  1. package net.dp.command.simpleremote; 
  2.  
  3. public class GarageDoorOpenCommand implements Command { 
  4.     GarageDoor garageDoor; 
  5.  
  6.     public GarageDoorOpenCommand(GarageDoor garageDoor) { 
  7.         this.garageDoor = garageDoor; 
  8.     } 
  9.  
  10.     public void execute() { 
  11.         garageDoor.up(); 
  12.     } 
  13.  
  14. package net.dp.command.simpleremote; 
  15.  
  16. public class LightOnCommand implements Command { 
  17.     Light light; 
  18.   
  19.     public LightOnCommand(Light light) { 
  20.         this.light = light; 
  21.     } 
  22.   
  23.     public void execute() { 
  24.         light.on(); 
  25.     } 
  26.  
  27. package net.dp.command.simpleremote; 
  28.  
  29. public class LightOffCommand implements Command { 
  30.     Light light; 
  31.   
  32.     public LightOffCommand(Light light) { 
  33.         this.light = light; 
  34.     } 
  35.   
  36.     public void execute() { 
  37.         light.off(); 
  38.     } 


下面是Invoker

 
 
  1. package net.dp.command.simpleremote; 
  2.  
  3. // 
  4. // This is the invoker 
  5. // 
  6. public class SimpleRemoteControl { 
  7.     Command slot; 
  8.   
  9.     public SimpleRemoteControl() {} 
  10.   
  11.     public void setCommand(Command command) { 
  12.         slot = command; 
  13.     } 
  14.   
  15.     public void buttonWasPressed() { 
  16.         slot.execute(); 
  17.     } 


调用关系

 
 
  1. package net.dp.command.simpleremote; 
  2.  
  3. public class RemoteControlTest { 
  4.     public static void main(String[] args) { 
  5.         SimpleRemoteControl remote = new SimpleRemoteControl(); 
  6.         Light light = new Light(); 
  7.         GarageDoor garageDoor = new GarageDoor(); 
  8.         LightOnCommand lightOn = new LightOnCommand(light); 
  9.         GarageDoorOpenCommand garageOpen = new GarageDoorOpenCommand(garageDoor); 
  10.  
  11.         remote.setCommand(lightOn); 
  12.         remote.buttonWasPressed(); 
  13.         remote.setCommand(garageOpen); 
  14.         remote.buttonWasPressed(); 
  15.     } 


下面是带有undo功能的命令模式示例
Command接口

 
 
  1. package net.dp.command.undo; 
  2.  
  3. public interface Command { 
  4.     public void execute(); 
  5.     public void undo(); 


所要封装的两个事物CeilingFan和Light(Receiver)

 
 
  1. package net.dp.command.undo; 
  2.  
  3. public class CeilingFan { 
  4.     public static final int HIGH = 3
  5.     public static final int MEDIUM = 2
  6.     public static final int LOW = 1
  7.     public static final int OFF = 0
  8.     String location; 
  9.     int speed; 
  10.   
  11.     public CeilingFan(String location) { 
  12.         this.location = location; 
  13.         speed = OFF; 
  14.     } 
  15.   
  16.     public void high() { 
  17.         speed = HIGH; 
  18.         System.out.println(location + " ceiling fan is on high"); 
  19.     } 
  20.   
  21.     public void medium() { 
  22.         speed = MEDIUM; 
  23.         System.out.println(location + " ceiling fan is on medium"); 
  24.     } 
  25.   
  26.     public void low() { 
  27.         speed = LOW; 
  28.         System.out.println(location + " ceiling fan is on low"); 
  29.     } 
  30.   
  31.     public void off() { 
  32.         speed = OFF; 
  33.         System.out.println(location + " ceiling fan is off"); 
  34.     } 
  35.   
  36.     public int getSpeed() { 
  37.         return speed; 
  38.     } 
  39.  
  40. package net.dp.command.undo; 
  41.  
  42. public class Light { 
  43.     String location; 
  44.     int level; 
  45.  
  46.     public Light(String location) { 
  47.         this.location = location; 
  48.     } 
  49.  
  50.     public void on() { 
  51.         level = 100
  52.         System.out.println("Light is on"); 
  53.     } 
  54.  
  55.     public void off() { 
  56.         level = 0
  57.         System.out.println("Light is off"); 
  58.     } 
  59.  
  60.     public void dim(int level) { 
  61.         this.level = level; 
  62.         if (level == 0) { 
  63.             off(); 
  64.         } 
  65.         else { 
  66.             System.out.println("Light is dimmed to " + level + "%"); 
  67.         } 
  68.     } 
  69.  
  70.     public int getLevel() { 
  71.         return level; 
  72.     } 


封装的具体命令(ConcreteCommand)
这里为了实现undo(),在execute()执行之前,会保存之前的对象状态。

 
 
  1. package net.dp.command.undo; 
  2.  
  3. public class CeilingFanHighCommand implements Command { 
  4.     CeilingFan ceilingFan; 
  5.     int prevSpeed; 
  6.   
  7.     public CeilingFanHighCommand(CeilingFan ceilingFan) { 
  8.         this.ceilingFan = ceilingFan; 
  9.     } 
  10.   
  11.     public void execute() { 
  12.         prevSpeed = ceilingFan.getSpeed(); 
  13.         ceilingFan.high(); 
  14.     } 
  15.   
  16.     public void undo() { 
  17.         if (prevSpeed == CeilingFan.HIGH) { 
  18.             ceilingFan.high(); 
  19.         } else if (prevSpeed == CeilingFan.MEDIUM) { 
  20.             ceilingFan.medium(); 
  21.         } else if (prevSpeed == CeilingFan.LOW) { 
  22.             ceilingFan.low(); 
  23.         } else if (prevSpeed == CeilingFan.OFF) { 
  24.             ceilingFan.off(); 
  25.         } 
  26.     } 
  27.  
  28. package net.dp.command.undo; 
  29.  
  30. public class CeilingFanMediumCommand implements Command { 
  31.     CeilingFan ceilingFan; 
  32.     int prevSpeed; 
  33.   
  34.     public CeilingFanMediumCommand(CeilingFan ceilingFan) { 
  35.         this.ceilingFan = ceilingFan; 
  36.     } 
  37.   
  38.     public void execute() { 
  39.         prevSpeed = ceilingFan.getSpeed(); 
  40.         ceilingFan.medium(); 
  41.     } 
  42.   
  43.     public void undo() { 
  44.         if (prevSpeed == CeilingFan.HIGH) { 
  45.             ceilingFan.high(); 
  46.         } else if (prevSpeed == CeilingFan.MEDIUM) { 
  47.             ceilingFan.medium(); 
  48.         } else if (prevSpeed == CeilingFan.LOW) { 
  49.             ceilingFan.low(); 
  50.         } else if (prevSpeed == CeilingFan.OFF) { 
  51.             ceilingFan.off(); 
  52.         } 
  53.     } 
  54.  
  55. package net.dp.command.undo; 
  56.  
  57. public class CeilingFanLowCommand implements Command { 
  58.     CeilingFan ceilingFan; 
  59.     int prevSpeed; 
  60.   
  61.     public CeilingFanLowCommand(CeilingFan ceilingFan) { 
  62.         this.ceilingFan = ceilingFan; 
  63.     } 
  64.   
  65.     public void execute() { 
  66.         prevSpeed = ceilingFan.getSpeed(); 
  67.         ceilingFan.low(); 
  68.     } 
  69.   
  70.     public void undo() { 
  71.         if (prevSpeed == CeilingFan.HIGH) { 
  72.             ceilingFan.high(); 
  73.         } else if (prevSpeed == CeilingFan.MEDIUM) { 
  74.             ceilingFan.medium(); 
  75.         } else if (prevSpeed == CeilingFan.LOW) { 
  76.             ceilingFan.low(); 
  77.         } else if (prevSpeed == CeilingFan.OFF) { 
  78.             ceilingFan.off(); 
  79.         } 
  80.     } 
  81.  
  82. package net.dp.command.undo; 
  83.  
  84. public class CeilingFanOnCommand implements Command { 
  85.     CeilingFan ceilingFan; 
  86.  
  87.     public CeilingFanOnCommand(CeilingFan ceilingFan) { 
  88.         this.ceilingFan = ceilingFan; 
  89.     } 
  90.     public void execute() { 
  91.         ceilingFan.high(); 
  92.     } 
  93.     public void undo() { 
  94.         ceilingFan.off(); 
  95.     } 
  96.  
  97. package net.dp.command.undo; 
  98.  
  99. public class CeilingFanOffCommand implements Command { 
  100.     CeilingFan ceilingFan; 
  101.     int prevSpeed; 
  102.   
  103.     public CeilingFanOffCommand(CeilingFan ceilingFan) { 
  104.         this.ceilingFan = ceilingFan; 
  105.     } 
  106.   
  107.     public void execute() { 
  108.         prevSpeed = ceilingFan.getSpeed(); 
  109.         ceilingFan.off(); 
  110.     } 
  111.   
  112.     public void undo() { 
  113.         if (prevSpeed == CeilingFan.HIGH) { 
  114.             ceilingFan.high(); 
  115.         } else if (prevSpeed == CeilingFan.MEDIUM) { 
  116.             ceilingFan.medium(); 
  117.         } else if (prevSpeed == CeilingFan.LOW) { 
  118.             ceilingFan.low(); 
  119.         } else if (prevSpeed == CeilingFan.OFF) { 
  120.             ceilingFan.off(); 
  121.         } 
  122.     } 
  123.  
  124. package net.dp.command.undo; 
  125.  
  126. public class DimmerLightOnCommand implements Command { 
  127.     Light light; 
  128.     int prevLevel; 
  129.  
  130.     public DimmerLightOnCommand(Light light) { 
  131.         this.light = light; 
  132.     } 
  133.  
  134.     public void execute() { 
  135.         prevLevel = light.getLevel(); 
  136.         light.dim(75); 
  137.     } 
  138.  
  139.     public void undo() { 
  140.         light.dim(prevLevel); 
  141.     } 
  142.  
  143. package net.dp.command.undo; 
  144.  
  145. public class DimmerLightOffCommand implements Command { 
  146.     Light light; 
  147.     int prevLevel; 
  148.  
  149.     public DimmerLightOffCommand(Light light) { 
  150.         this.light = light; 
  151.         prevLevel = 100
  152.     } 
  153.  
  154.     public void execute() { 
  155.         prevLevel = light.getLevel(); 
  156.         light.off(); 
  157.     } 
  158.  
  159.     public void undo() { 
  160.         light.dim(prevLevel); 
  161.     } 
  162.  
  163. package net.dp.command.undo; 
  164.  
  165. public class LightOnCommand implements Command { 
  166.     Light light; 
  167.   
  168.     public LightOnCommand(Light light) { 
  169.         this.light = light; 
  170.     } 
  171.   
  172.     public void execute() { 
  173.         light.on(); 
  174.     } 
  175.   
  176.     public void undo() { 
  177.         light.off(); 
  178.     } 
  179.  
  180. package net.dp.command.undo; 
  181.  
  182. public class LightOffCommand implements Command { 
  183.     Light light; 
  184.   
  185.     public LightOffCommand(Light light) { 
  186.         this.light = light; 
  187.     } 
  188.   
  189.     public void execute() { 
  190.         light.off(); 
  191.     } 
  192.   
  193.     public void undo() { 
  194.         light.on(); 
  195.     } 


下面是一个空对象(null object)。可以将处理null的责任转移给空对象。举例来说,遥控器不可能一出厂就设置了有意义的命令对象,所以提供了NoCommand对象作为代用品,当调用它的execute()时,它不会做任何事情。

 
 
  1. package net.dp.command.undo; 
  2.  
  3. public class NoCommand implements Command { 
  4.     public void execute() { } 
  5.     public void undo() { } 


下面是Invoker

 
 
  1. package net.dp.command.undo; 
  2.  
  3.  
  4. // 
  5. // This is the invoker 
  6. // 
  7. public class RemoteControlWithUndo { 
  8.     Command[] onCommands; 
  9.     Command[] offCommands; 
  10.     Command undoCommand; 
  11.   
  12.     public RemoteControlWithUndo() { 
  13.         onCommands = new Command[7]; 
  14.         offCommands = new Command[7]; 
  15.   
  16.         Command noCommand = new NoCommand(); 
  17.         for(int i=0;i<7;i++) { 
  18.             onCommands[i] = noCommand; 
  19.             offCommands[i] = noCommand; 
  20.         } 
  21.         undoCommand = noCommand; 
  22.     } 
  23.   
  24.     public void setCommand(int slot, Command onCommand, Command offCommand) { 
  25.         onCommands[slot] = onCommand; 
  26.         offCommands[slot] = offCommand; 
  27.     } 
  28.   
  29.     public void onButtonWasPushed(int slot) { 
  30.         onCommands[slot].execute(); 
  31.         undoCommand = onCommands[slot]; 
  32.     } 
  33.   
  34.     public void offButtonWasPushed(int slot) { 
  35.         offCommands[slot].execute(); 
  36.         undoCommand = offCommands[slot]; 
  37.     } 
  38.   
  39.     public void undoButtonWasPushed() { 
  40.         undoCommand.undo(); 
  41.     } 
  42.   
  43.     public String toString() { 
  44.         StringBuffer stringBuff = new StringBuffer(); 
  45.         stringBuff.append("\n------ Remote Control -------\n"); 
  46.         for (int i = 0; i < onCommands.length; i++) { 
  47.             stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName() 
  48.                 + "    " + offCommands[i].getClass().getName() + "\n"); 
  49.         } 
  50.         stringBuff.append("[undo] " + undoCommand.getClass().getName() + "\n"); 
  51.         return stringBuff.toString(); 
  52.     } 


调用关系

 
 
  1. package net.dp.command.undo; 
  2.  
  3. public class RemoteLoader { 
  4.   
  5.     public static void main(String[] args) { 
  6.         RemoteControlWithUndo remoteControl = new RemoteControlWithUndo(); 
  7.   
  8.         Light livingRoomLight = new Light("Living Room"); 
  9.   
  10.         LightOnCommand livingRoomLightOn = 
  11.                 new LightOnCommand(livingRoomLight); 
  12.         LightOffCommand livingRoomLightOff = 
  13.                 new LightOffCommand(livingRoomLight); 
  14.   
  15.         remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff); 
  16.   
  17.         remoteControl.onButtonWasPushed(0); 
  18.         remoteControl.offButtonWasPushed(0); 
  19.         System.out.println(remoteControl); 
  20.         remoteControl.undoButtonWasPushed(); 
  21.         remoteControl.offButtonWasPushed(0); 
  22.         remoteControl.onButtonWasPushed(0); 
  23.         System.out.println(remoteControl); 
  24.         remoteControl.undoButtonWasPushed(); 
  25.  
  26.         CeilingFan ceilingFan = new CeilingFan("Living Room"); 
  27.    
  28.         CeilingFanMediumCommand ceilingFanMedium = 
  29.                 new CeilingFanMediumCommand(ceilingFan); 
  30.         CeilingFanHighCommand ceilingFanHigh = 
  31.                 new CeilingFanHighCommand(ceilingFan); 
  32.         CeilingFanOffCommand ceilingFanOff = 
  33.                 new CeilingFanOffCommand(ceilingFan); 
  34.   
  35.         remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff); 
  36.         remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff); 
  37.    
  38.         remoteControl.onButtonWasPushed(0); 
  39.         remoteControl.offButtonWasPushed(0); 
  40.         System.out.println(remoteControl); 
  41.         remoteControl.undoButtonWasPushed(); 
  42.   
  43.         remoteControl.onButtonWasPushed(1); 
  44.         System.out.println(remoteControl); 
  45.         remoteControl.undoButtonWasPushed(); 
  46.     } 


设置宏命令,可以将部分命令组合在一起依次连续触发或关闭

 
 
  1. package net.dp.command.party; 
  2.  
  3. public class MacroCommand implements Command { 
  4.     Command[] commands; 
  5.   
  6.     public MacroCommand(Command[] commands) { 
  7.         this.commands = commands; 
  8.     } 
  9.   
  10.     public void execute() { 
  11.         for (int i = 0; i < commands.length; i++) { 
  12.             commands[i].execute(); 
  13.         } 
  14.     } 
  15.   
  16.     public void undo() { 
  17.         for (int i = 0; i < commands.length; i++) { 
  18.             commands[i].undo(); 
  19.         } 
  20.     } 


调用关系

 
 
  1. package net.dp.command.party; 
  2.  
  3. public class RemoteLoader { 
  4.  
  5.     public static void main(String[] args) { 
  6.  
  7.         RemoteControl remoteControl = new RemoteControl(); 
  8.  
  9.         Light light = new Light("Living Room"); 
  10.         TV tv = new TV("Living Room"); 
  11.         Stereo stereo = new Stereo("Living Room"); 
  12.         Hottub hottub = new Hottub(); 
  13.   
  14.         LightOnCommand lightOn = new LightOnCommand(light); 
  15.         StereoOnCommand stereoOn = new StereoOnCommand(stereo); 
  16.         TVOnCommand tvOn = new TVOnCommand(tv); 
  17.         HottubOnCommand hottubOn = new HottubOnCommand(hottub); 
  18.         LightOffCommand lightOff = new LightOffCommand(light); 
  19.         StereoOffCommand stereoOff = new StereoOffCommand(stereo); 
  20.         TVOffCommand tvOff = new TVOffCommand(tv); 
  21.         HottubOffCommand hottubOff = new HottubOffCommand(hottub); 
  22.  
  23.         Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn}; 
  24.         Command[] partyOff = { lightOff, stereoOff, tvOff, hottubOff}; 
  25.   
  26.         MacroCommand partyOnMacro = new MacroCommand(partyOn); 
  27.         MacroCommand partyOffMacro = new MacroCommand(partyOff); 
  28.   
  29.         remoteControl.setCommand(0, partyOnMacro, partyOffMacro); 
  30.   
  31.         System.out.println(remoteControl); 
  32.         System.out.println("--- Pushing Macro On---"); 
  33.         remoteControl.onButtonWasPushed(0); 
  34.         System.out.println("--- Pushing Macro Off---"); 
  35.         remoteControl.offButtonWasPushed(0); 
  36.     } 


《Head First Design Pattern》源代码下载 http://zhangjunhd.blog.51cto.com/113473/69908

本文出自 “子 孑” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/409996

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值