『StuQ技术人写作输出行动计划』大本营

命令(Command)模式

2016-11-05  本文已影响61人  _时光念你

一 前言

离开具体业务需求谈设计模式都是耍流氓,OOP的世界里出现设计模式是为了让程序更有弹性,易于扩展。
而且经过这么多年的发展,前辈们从具体的业务需求抽象出很多种的设计模式,这次我们就来探讨一下其中之命令(Command)模式,代码用例是Java语言。

二 需求场景#

假设现在有这样一个需求:我们公司接到一个订单,要求生产一个电器遥控器,要求每次按右边的ON/OFF按钮,左边对应的插槽上的电器会响应该命令,而且厂家已经提供了所有的电器的使用接口,重要的是要考虑左边的插槽对应的电器以后可能会换成其他的电器,按下最下面的撤销按钮会执行与上次命令相反的命令,比如上次ON->撤销就是OFF,遥控器如图:

遥控器.png

厂家给的电器接口如下:

// 电灯的接口
public void on(); // 开灯
public void off();// 关灯
// 电视的接口
public void onTelevision(); // 开电视
public void offTelevision();// 关电视
// 还有其他各种电器...

还有其他的电器接口,但是这些接口必定有开和关两个基本,接口的名字可能是不一样的,因为我们不可能让厂家修改接口名称。呃...毕竟顾客就是上帝!

三 一般的实现思路

按照一般的思维逻辑我们可能这么写:

// 伪代码
// 遥控器
public class RemoteController{
      // 第i个按钮的on被点击
      public void onButtonWhenPush(int index){
        1.先找到对应i的位置的电器
        2.判断对应的电器的类型,因为每个不同的电器的接口方法不是一样的,所以需要强制类型转换一下
        3.获得电器类型,执行该电器的开方法,比如电视的话执行onTelevision(),电灯执行on(),其他电器类似
       }
       // 第i个按钮的off被点击
      public void offButtonWhenPush(int index){
         // 跟onButtonWhenPush方法的实现逻辑类似
    }
}

对了,还有一个撤销按钮没有实现,我们可以定义一个变量来记录刚刚执行命令的电器,并且每个电器类都要有一个记录电器状态的boolean值,如果这样写的,厂商提供的接口就会被我们改变,这当然不是我们想要的设计.如果我们能将每次电器执行的操作封装成一个对象,那会怎么样呢?
引入今天的主角-命令模式,先看看定义:
命令模式 将请求封装成"对象",以便使用不同的请求、队列、或者日志来参数化其他对象.命令模式也支持可撤销的操作.

四 命令模式实现

电器:
/// 电灯类
public class Light {
 public void on(){
  System.out.println("Light - ON");
 }
 
 public void off(){
  System.out.println("Light - OFF");
 }
}
/// 电视类
public class Television {
 
 public void onTelevision(){
  System.out.println("Television - ON");
 }
 
 public void offTelevision(){
  System.out.println("Television - OFF");
 }
}
命令接口:
/// 命令接口
public interface Command {
 // 执行命令
 public void execute();
 // 撤销
 public void undo();
}
电灯命令类(电视类也是差不多的,厂商给的什么接口就写什么接口):
/// 开灯命令
public class LightOnCommand implements Command{
 Light light;
 
 LightOnCommand(Light light){
  this.light = light;
 }
 public void execute(){
  light.on();
 }
 public void undo(){
  light.off();
 }
}

/// 关灯命令
public class LightOffCommand implements Command{
 Light light;
 
 LightOffCommand(Light light){
  this.light = light;
 }
 public void execute(){
  light.off();
 }
 public void undo(){
  light.on();
 }
}
空命令(这也是一种设计模式):
public class NullCommand implements Command{
 public void execute(){
  System.out.println("空指令被执行");
 }
 
 public void undo(){
  System.out.println("撤销了空指令");
 }
}
遥控器:
/// 遥控器
public class RemoteController {
 public Command undoCommand; // 上一次指令,用来执行undo
 public static final int componentCount = 5;
 Command[] onCommands;
 Command[] offCommands;

 public RemoteController()
 {
  this.onCommands = new Command[componentCount];
  this.offCommands = new Command[componentCount];
  
  // 空命令也是一种设计模式
  NullCommand nc = new NullCommand();
  for(int i = 0;i < componentCount;++i){
   this.onCommands[i] = nc;
   this.offCommands[i] = nc;
  }
 }
 
 /**
  * 设置对应插槽的命令
  **/
 public void setCommand(int index,Command onCommand,Command offCommand ){
  onCommands[index] = onCommand;
  offCommands[index] = offCommand;
 }
 
 /**
  * 打开
  **/
 public void onButtonPushed(int index){
  onCommands[index].execute();
  undoCommand = onCommands[index];
 }
 
 /**
  * 关闭
  **/
 public void offButtonPushed(int index){
  offCommands[index].execute();
  undoCommand = offCommands[index];
 }
 
 /**
  * 撤销
  **/
 public void undoButtonPushed(){
  undoCommand.undo();
 }

}
现在来进行测试:

public class CommandDesignPattern {
 public static void main(String[] args)
 {
  // 电器
  Light light1 = new Light();
  Light light2 = new Light();
  
  Television tv1 = new Television();
  Television tv2 = new Television();
  
  // 开命令
  LightOnCommand lightOnCommand1 = new LightOnCommand(light1);
  LightOnCommand lightOnCommand2 = new LightOnCommand(light2);
  TelevisionOnCommand televisionOnCommand1 = new TelevisionOnCommand(tv1);
  TelevisionOnCommand televisionOnCommand2 = new TelevisionOnCommand(tv2);

  // 空命令
  NullCommand nullCommand = new NullCommand();
  // 关命令
  LightOffCommand lightOffCommand1 = new LightOffCommand(light1);
  LightOffCommand lightOffCommand2 = new LightOffCommand(light2);
  TelevisionOffCommand televisionOffCommand1 = new TelevisionOffCommand(tv1);
  TelevisionOffCommand televisionOffCommand2 = new TelevisionOffCommand(tv2);
  
  // 设置遥控器对应插槽的命令
  RemoteController remoteController = new RemoteController();
  remoteController.setCommand(0, lightOnCommand1, lightOffCommand1);
  remoteController.setCommand(1, lightOnCommand2, lightOffCommand2);
  remoteController.setCommand(2, nullCommand, nullCommand);
  remoteController.setCommand(3, televisionOnCommand1, televisionOffCommand1);
  remoteController.setCommand(4, televisionOnCommand2, televisionOffCommand2);
  
  // 测试遥控器
  remoteController.onButtonPushed(0); // 打开槽1的灯
  remoteController.offButtonPushed(0); // 关闭槽1的灯
  remoteController.onButtonPushed(3); // 打开槽4的电视
  remoteController.offButtonPushed(3); // 关闭槽4的电视

  remoteController.undoButtonPushed();// 撤销上一次操作
 }
}
执行结果:
Light - ON
Light - OFF
Television - ON
Television - OFF
Television - ON
遥控器流程图.png

参考自:<<Head First设计模式>>

上一篇下一篇

猜你喜欢

热点阅读