设计模式从入门到放弃(十四)命令模式

基本概念

命令模式 command pattern ,将请求封装成一个命令对象,传递给调用者,调用者找到具体可以处理该命令的对象,由该对象去执行具体逻辑。使得请求发送者和请求的接受者彼此解耦,使得对象的调用关系更加灵活。

uml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8n2Vbn6k-1588929623457)(C:\Users\denglw\AppData\Roaming\Typora\typora-user-images\image-20200508160724076.png)]

角色分析

Invoker 调用者 命令发起者 类似一个总控

Command 命令抽象接口 包含执行和撤销操作

Receiver 接受者被聚合到具体的命令中执行具体的逻辑

ConcreteCommand 将命令和具体接受者的动作绑定实现execute和undo逻辑

代码实现

现在有一套智能家居需要控制,我们抽取一个通用调控器(Invoker)来控制各个家居(Receiver)的开关功能(ConcreteCommand)。

public interface Command {

    /**
     * 执行命令
     */
    void execute();

    /**
     * 撤销操作
     */
    void undo();
}
// Recevier 具体命令的执行者
public class LightReceiver {

    public void on(){
        System.out.println("灯开了");
    }

    public void off(){
        System.out.println("灯关了");
    }
}

// 灯打开的命令
public class LightOnCommand implements Command {
	
    // 将灯的具体操作接受者聚合到命令中
    private final LightReceiver lightReceiver;

    public LightOnCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        // 打开
        lightReceiver.on();
    }

    @Override
    public void undo() {
        // 关闭
        lightReceiver.off();
    }
}

// 灯关闭
public class LightOffCommand implements Command {

    private final LightReceiver lightReceiver;

    public LightOffCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        // 调用灯关闭
        lightReceiver.off();
    }

    @Override
    public void undo() {
        // 灯关闭的取消就是打开
        lightReceiver.on();
    }
}

// 空命令 主要为了避免空指针
public class NoCommand implements Command {
    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}
// Invoker对象
public class RemoteInvoker {
    // 打开命令数组
    Command[] onCommands = new Command[5];
    // 关闭命令数组
    Command[] offCommands = new Command[5];
    // 上一个执行命令 用于执行undo
    Command preCommand = new NoCommand();

    // 初始化全部为空命令 避免了非空判断
    public RemoteInvoker() {
        // 初始化
        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    /**
     * 设置命令
     * @param index 命令存在位置 相当于遥控器上面的哪一个按钮
     * @param isOn 是不是开命令
     * @param command 具体哪个命令
     */
    public void setCommand(int index, boolean isOn, Command command) {
        if (isOn) {
            onCommands[index] = command;
        } else {
            offCommands[index] = command;
        }
    }

    /**
     * 按开命令
     * @param index 哪一个命令
     */
    public void pressOffButton(int index) {
        offCommands[index].execute();
        preCommand = offCommands[index];
    }

    /**
     * 按关闭命令
     * @param index
     */
    public void pressOnButton(int index){
        onCommands[index].execute();
        preCommand = onCommands[index];
    }

    /**
     * 取消上一次操作
     */
    public void undo(){
        preCommand.undo();
    }
}
// 使用测试
public class CommandTest {

    public static void main(String[] args) {
        // 先创建接受者
        LightReceiver lightReceiver = new LightReceiver();
        // 创建命令 聚合就饿守着
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
        // 创建Invoker 命令执行者
        RemoteInvoker remoteInvoker = new RemoteInvoker();
        // 设置命令
        remoteInvoker.setCommand(0, true, lightOnCommand);
        remoteInvoker.setCommand(0, false, lightOffCommand);

        //调用执行
        remoteInvoker.pressOnButton(0);
        remoteInvoker.pressOffButton(0);
        // 撤销操作
        remoteInvoker.undo();
    }
}
/** 最终输出
灯开了
灯关了
灯开了
*/

使用细节

命令模式主要想把请求的对象和执行请求的对象进行解耦,调用者只需要调用命令对象的execute方法,就可以让接受者工作,无需知道具体的接受者是谁,如何实现。本质上执行工作其实是接受者,命令对象起到一个桥梁的作用。

命令模式容易实现对请求的撤销操作,空命令可以为我们省略非空判断。

命令模式可能导致许多的命令类,不同的操作对应一个命令类,导致命令类过多增加的业务的复杂的。

猜你喜欢

转载自blog.csdn.net/woshiwjma956/article/details/106001992