命令模式

在我们编程应用中或者生活之中。我们希望用一个统一的遥控器,这个遥控器可以对家电进行统一的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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值