设计模式-命令模式

问题背景

1)随着现在科技越来越先进,我们在家庭中对物品的开关都不需要亲自走过去来进行了。我们只需要通过手机APP中的按键来远程执行这个命令。
2)其实这就是命令模式,使用者完全不需要懂这个命令如何执行,谁来执行,使用者只需要发送命令即可。
3)命令模式可将“动作的请求者”从“动作的执行者对象中解耦出来
在这里插入图片描述

命令模式

基本介绍

1)命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道彼请求的操作是哪个
我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计
2)命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
3)在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
4)通俗易懂的理解,将军发布命令,士兵去执行。其中有几个角色,将军(命令发布者)、士兵 (命令的具体执行者) 、命令(连接将军和士兵)。
Invoker是调用者 (将军),Receiver是被调用者 (士兵),MyCommand是命令,实现了Command接口,持有接收对象
5)命令的发送者完全不需知道谁来执行,只需要发送

UML类图

在这里插入图片描述
1)Invoker是调用者角色
2)Command是命令调用者,需要执行所有命令都在这里,可以是接口或者抽象类
3)Receiver是接收者,具体执行命令的角色
4)ConcreteCommand将一个接收者对象与一个动作绑定,调用接收者相应的操作
5)不理解可结合实际问题解决得UML类图来理解

解决方案

UML类图

在这里插入图片描述
1)原始物品LightReceiver有开关方法
2)继承Command接口创建等得开关命令,开灯命令撤回方法就是关灯,关灯方法撤回方法就是开灯
3)创建一个RemoteController来保存这些命令,调用得时候直接调用RemoteController类即可
4)NoCommand是一个空命令,可以简化我们的判空操作
5)RemoteController类中有两个属性,map用来保存命令,stack用来记录执行的命令

代码示例

/**
 * 灯
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public class LightReceiver {
    public void on() {
        System.out.println("开灯");
    }

    public void off() {
        System.out.println("关灯");
    }
}
/**
 * 命令接口
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public interface Command {
    /**
     * 执行命令
     */
    void execute();

    /**
     * 撤回命令
     */
    void undo();
}
/**
 * 开灯命令
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class LightOnCommand implements Command {

    private LightReceiver lightReceiver = new LightReceiver();


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

    @Override
    public void undo() {
        lightReceiver.off();
    }
}
/**
 * 关灯命令
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class LightOffCommand implements Command {

    private LightReceiver lightReceiver = new LightReceiver();


    @Override
    public void execute() {
        lightReceiver.off();
    }

    @Override
    public void undo() {
        lightReceiver.on();
    }
}
/**
 * 空命令
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class NoCommand implements Command {
    @Override
    public void execute() {
        System.out.println("空命令");
    }

    @Override
    public void undo() {
        System.out.println("空命令");
    }
}
/**
 * 控制界面
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class RemoteController {

    /**
     * 用来保存命令的设置信息
     */
    private Map<String, Command> map = new HashMap<>(8);

    /**
     * 用来保存执行的命令 【使用栈】 【用于命令撤回】
     */
    private Stack<Command> stack = new Stack<>();

    /**
     * 设置命令
     *
     * @param name
     * @param command
     */
    public void setCommond(String name, Command command) {
        map.put(name, command);
    }

    /**
     * 开
     *
     * @param name
     */
    public void on(String name) {
        Command command = map.getOrDefault(name, new NoCommand());
        command.execute();
        stack.push(command);
    }

    /**
     * 关
     *
     * @param name
     */
    public void off(String name) {
        Command command = map.getOrDefault(name, new NoCommand());
        command.execute();
        stack.push(command);
    }

    /**
     * 撤回
     *
     */
    public void undo() {
        if (stack.isEmpty()) {
            new NoCommand().undo();
            return;
        }
        Command pop = stack.pop();
        pop.undo();
    }
}

我们来设置命令并使用他们

public class Client {
    public static void main(String[] args) {
        // 创建一个控制界面
        RemoteController remoteController = new RemoteController();

        // 设置命令
        remoteController.setCommond("灯-开", new LightOnCommand());
        remoteController.setCommond("灯-关", new LightOffCommand());


        // 执行命令
        remoteController.on("灯-开");

        // 回撤命令
        remoteController.undo();
        remoteController.undo();
    }
}

执行结果

在这里插入图片描述

我们来增加一种设备,加入到控制界面

/**
 * 电视
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public class TelevisionReceiver {
    public void on() {
        System.out.println("打开电视");
    }

    public void off() {
        System.out.println("关闭电视");
    }
}
/**
 * 打开电视命令
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class TelevisionOnCommand implements Command {

    private TelevisionReceiver televisionReceiver = new TelevisionReceiver();

    @Override
    public void execute() {
        televisionReceiver.on();
    }

    @Override
    public void undo() {
        televisionReceiver.off();
    }
}
/**
 * 关闭电视命令
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class TelevisionOffCommand implements Command {

    private TelevisionReceiver televisionReceiver = new TelevisionReceiver();

    @Override
    public void execute() {
        televisionReceiver.off();
    }

    @Override
    public void undo() {
        televisionReceiver.on();
    }
}

将新设备的命令增加到控制界面

public class Client {
    public static void main(String[] args) {
        // 创建一个控制界面
        RemoteController remoteController = new RemoteController();

        // 设置命令
        remoteController.setCommond("灯-开", new LightOnCommand());
        remoteController.setCommond("灯-关", new LightOffCommand());
        remoteController.setCommond("电视-开", new TelevisionOnCommand());
        remoteController.setCommond("电视-关", new TelevisionOffCommand());

        // 执行命令
        remoteController.on("灯-开");
        remoteController.on("电视-开");
        remoteController.on("电视-关");

        // 回撤命令
        remoteController.undo();
        remoteController.undo();
    }
}

执行结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值