命令模式

来源:互联网 发布:java输出2到200的素数 编辑:程序博客网 时间:2024/06/05 14:17
在我们编程应用中或者生活之中。我们希望用一个统一的遥控器,这个遥控器可以对家电进行统一的off和on操作,但是这些遥控器却不需要知道这些家电自动化的细节。
命令模式可以将“动作的请求者”从“动作的执行者”对象中解耦。请求者为遥控器,执行者为家电。
做法是把请求封装成一个特定的对象(如电灯对象)。所以如果对每个按钮都存储一个命令对象,那么当按下按钮的时候,就可以请命令对象做相关的工作。遥控器并不需要知道工作内容是什么,只要有个命令对象能和正确的对象沟通,把事情做好就行了。这样便实现了请求者与执行者之间的解耦。

首先我们要编写统一的命令接口

public interface Command {    public void execute();}
然后创建一个电灯,该电灯有关闭和打开的操作。
class Light{    public void on(){        System.out.println("打开电灯");    }    public void off(){        System.out.println("关闭电灯");    }}
原始的操作是让命令的调用者持有该灯操作如下
public class SimpleRemoteControl {       public void lightControl(String type){           Light light=new Light();           if(type.equals("off"))               light.off();           else light.on();       }}

这样会造成请求者与执行者之间的耦合。如果该电灯还有调节灯光强弱的功能的话,我们就要对该对象中的方法进行修改,这样违反了设计原则“对修改关闭,对扩展开发”。
命令模式将这种控制提出,封装成对象。
class LightOnCommand implements Command{    Light light;    @Override    public void execute() {        // TODO Auto-generated method stub        light.on();    }    public LightOnCommand(Light light){        this.light=light;    }}class LightOffCommand implements Command{    Light light;    @Override    public void execute() {        // TODO Auto-generated method stub        light.off();    }    public LightOffCommand(Light light){        this.light=light;    }}
这样,请求者只需要知道调用该命令对某家电控制,但是不知道该控制的细节,实现了请求者与执行者之间的解耦。
public class SimpleRemoteControl {      Command slot;      public SimpleRemoteControl(){      }      public void setCommand(Command command){          slot=command;      }      public void buttonWasPressed(){          slot.execute();      }}
但是我们并不想一个操作对应一个遥控器,我们想用一个遥控器对所有家电进行统一的管理。这样我们可以在SimpleRemoteControl类中的成员变量Command设置成数组,来进行统一的管理,代码如下:

public class SimpleRemoteControl {      Command[] onCommands;//统一的开按钮命令      Command[] offCommands;//统一的关按钮命令      public SimpleRemoteControl(){          onCommands=new Command[7];          offCommands=new Command[7];          for(int i=0;i<7;i++){              onCommands[i]=new NoCommand();              offCommands[i]=new NoCommand();          }      }      public void setCommand(int slot,Command onCommand,Command offCommand){          onCommands[slot]=onCommand;          offCommands[slot]=offCommand;      }      public void buttonWasPressed(int slot){          onCommands[slot].execute();      }      public void buttonWasOff(int slot){          offCommands[slot].execute();      }}
其中NoCommand为一个实现Command接口的空类,这样做的目的是可以省去在按钮按下判断按钮是否为空的操作。
class NoCommand implements Command{    @Override    public void execute() {        // TODO Auto-generated method stub        System.out.println("该按钮无效");    }}
该模式还能扩展,提供撤销功能。我们生活中比如电视遥控器,经常想回到上一个看的频道,这样我们需要撤销当前操作。在编程中,其实我们只需要记录上一个操作是什么即可。如果我们想撤销多个命令,就要将该记录上一个操作的变量定义为一个堆栈,用堆栈来存储每次新操作的命令,撤销只需要将该命令从堆栈中移除。当然Command接口也要新添加undo撤销方法,并让子类实现该方法。

public interface Command {    public void execute();    public void undo();//撤销命令}class NoCommand implements Command{    @Override    public void execute() {        // TODO Auto-generated method stub        System.out.println("该按钮无效");    }    @Override    public void undo() {        // TODO Auto-generated method stub    }}class LightOnCommand implements Command{    Light light;    @Override    public void execute() {        // TODO Auto-generated method stub        light.on();    }    public LightOnCommand(Light light){        this.light=light;    }    @Override    public void undo() {        // TODO Auto-generated method stub        light.off();    }}class LightOffCommand implements Command{    Light light;    @Override    public void execute() {        // TODO Auto-generated method stub        light.off();    }    public LightOffCommand(Light light){        this.light=light;    }    @Override    public void undo() {        // TODO Auto-generated method stub        light.on();    }}public class SimpleRemoteControl {      Command[] onCommands;      Command[] offCommands;      Stack<Command> stack;//撤销栈,来存储命令记录      public SimpleRemoteControl(){          onCommands=new Command[7];          offCommands=new Command[7];          for(int i=0;i<7;i++){              onCommands[i]=new NoCommand();              offCommands[i]=new NoCommand();          }          stack=new Stack<>();      }      public void setCommand(int slot,Command onCommand,Command offCommand){          onCommands[slot]=onCommand;          offCommands[slot]=offCommand;      }      public void buttonWasPressed(int slot){          onCommands[slot].execute();          stack.push(onCommands[slot]);      }      public void buttonWasOff(int slot){          offCommands[slot].execute();          stack.push(offCommands[slot]);      }    public void undoButton(){          if(!stack.isEmpty())          {              System.out.print("撤销命令:");              stack.peek().execute();              System.out.print("执行:");              stack.pop().undo();          }      }}
main方法

 public static void main(String[] args) {        // TODO Auto-generated method stub        SimpleRemoteControl remoteControl=new SimpleRemoteControl();        Light living=new Light();        LightOnCommand lightOnCommand=new LightOnCommand(living);        LightOffCommand lightOffCommand=new LightOffCommand(living);        remoteControl.setCommand(0, lightOnCommand, lightOffCommand);        remoteControl.buttonWasPressed(0);        remoteControl.buttonWasOff(0);        System.out.println("撤销命令1:");        remoteControl.undoButton();        System.out.println("撤销命令2:");        remoteControl.undoButton();    }

命令模式:将请求封装成对象,这可以让你使用不同的请求、队列或者日志请求来参数化其他对象。命令模式也可以支持撤销操作。
命令模式降低了系统的耦合度,同时可以很容易的让新的命令添加进去,不用对原对象进行修改。
但是命令模式可能会导致系统过多的命令类。因为每一个命令都要实现Command接口生成新的类。
使用场景为 

1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。

2.系统需要在不同的时间指定请求、将请求排队和执行请求。

3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。

4.系统需要将一组操作组合在一起,即支持宏命令。

以上是自己的浅见,不喜勿喷哈。有错误希望指正。








1 0
原创粉丝点击