命令模式

2021-01-13  本文已影响0人  梦星夜雨

前言

命令模式(Command Pattern)属于数据驱动当设计模式,是一种行为模式。将请求封装成对象,以便使用不同的请求/队列或日志来参数化其他对象。命令模式也支持可撤销的操作。
当需要将发出请求对象和执行请求对象解耦的时候,使用命令模式。
对行为请求者和行为实现者进行解耦,常用于对行为进行记录、撤销或重做、事务等处理。

命令模式的代码实现

我们以遥控器为例,家里有电扇,灯等家具。我们想要一个遥控就能控制相应等家具那么该如何设计呢?
首先我们创建一个实现命令等接口:

public interface Command {
    public void execute();
}

然后,对于打开灯和关闭灯的命令进行封装:

public class Light {

    public Light() {
    }

    public void on() {
        System.out.println("Light is on");
    }

    public void off() {
        System.out.println("Light is off");
    }
}
public class LightOnCommand implements Command {
    Light light;
  
    public LightOnCommand(Light light) {
        this.light = light;
    }
 
    public void execute() {
        light.on();
    }
}
public class LightOffCommand implements Command {
    Light light;
 
    public LightOffCommand(Light light) {
        this.light = light;
    }
 
    public void execute() {
        light.off();
    }
}

那么我们该怎么在遥控器上使用呢?我们定义一个控制类SimpleRemoteControl

public class SimpleRemoteControl {
    Command onCommand;
    Command offCommand;
 
    public SimpleRemoteControl() {}
 
    public void setCommand(Command onCommand, Command offCommand) {
        this.onCommand = onCommand;
        this.offCommand = offCommand;
    }
 
    public void onButtonWasPressed() {
        onCommand.execute();
    }

    public void offButtonWasPressed() {
        offCommand.execute();
    }
}

我们可以看到当我们传入相应的Command实现类,按下按钮后会执行execute()方法,然后执行相应的操作。
这里我们可能需要一个撤销的功能,那么,我们在Command接口中加入undo()方法。

public interface Command {
    public void execute();
    public void undo();
}

那么相应的关灯和开灯的命令类有如下变化:

public class LightOnCommand implements Command {
    Light light;
    public LightOnCommand(Light light) {
        this.light = light;
    }
 
    public void execute() {
        light.on();
    }
 
    public void undo() {
        light.off();
    }
}
public class LightOffCommand implements Command {
    Light light;
    public LightOffCommand(Light light) {
        this.light = light;
    }
 
    public void execute() {
        light.off();
    }
 
    public void undo() {
        light.on();
    }
}

这么做看似很简单,但当我们第二次按下但时候,发现并不能做到再次撤销的结果。所以这个时候,我们需要在SimpleRemoteControl类中添加一个记录最后命令的变量。如下所示:

public class SimpleRemoteControl {
    private Command onCommand;
    private Command offCommand;
    private Command undoCommand;
 
    public SimpleRemoteControl() {}
 
    public void setCommand(Command onCommand, Command offCommand) {
        this.onCommand = onCommand;
        this.offCommand = offCommand;
    }
 
    public void onButtonWasPressed() {
        onCommand.execute();
        undoCommand = onCommand;
    }

    public void offButtonWasPressed() {
        offCommand.execute();
        undoCommand = offCommand;
    }
    public void undoButtonWasPushed() {
        if(null != undoCommand) {
            undoCommand.undo();
        }
    }
}

测试类和测试结果如下:

public class RemoteControlTest {
   public static void main(String[] args) {
       SimpleRemoteControl remote = new SimpleRemoteControl();
       Light light = new Light();
       LightOnCommand lightOn = new LightOnCommand(light);
       LightOffCommand lightOff = new LightOffCommand(light);

       remote.setCommand(lightOn,lightOff);
       remote.onButtonWasPressed();
       remote.undoButtonWasPushed();
       remote.offButtonWasPressed();
       remote.undoButtonWasPushed();
   }
   
}
Light is on
Light is off
Light is off
Light is on

同理,关于电扇的操作大同小异,由于篇幅问题就不赘述,并且我们还可以针对风扇的速度进行相应的设计。我们可以通过设计不同的具体命令类来实现不同的功能,比如一键开灯,同时关闭所有电器。
相信通过以上的说明,了解了命令模式是如何工作和使用的。同时命令模式具有以下优缺点:
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

上一篇 下一篇

猜你喜欢

热点阅读