行为型设计模式---命令模式

设计模式

序号内容链接地址
1设计模式七大原则https://blog.csdn.net/qq_39668819/article/details/115390615
2创建型设计模式–工厂模式https://blog.csdn.net/qq_39668819/article/details/115375928
3创建型设计模式–抽象工厂模式https://blog.csdn.net/qq_39668819/article/details/115390992
4创建型设计模式–单例模式https://blog.csdn.net/qq_39668819/article/details/115396191
5创建型设计模式–建造者模式https://blog.csdn.net/qq_39668819/article/details/115396212
6创建型设计模式—原型模式https://blog.csdn.net/qq_39668819/article/details/115396227
7结构型设计模式—代理模式https://blog.csdn.net/qq_39668819/article/details/115480346
8结构型设计模式—适配器模式https://blog.csdn.net/qq_39668819/article/details/115499090
9结构型设计模式—桥接模式https://blog.csdn.net/qq_39668819/article/details/115560823
10结构型设计模式—装饰模式https://blog.csdn.net/qq_39668819/article/details/115582291
11结构型设计模式—外观模式https://blog.csdn.net/qq_39668819/article/details/115643900
12结构型设计模式—享元模式https://blog.csdn.net/qq_39668819/article/details/115680930
13结构型设计模式—组合模式https://blog.csdn.net/qq_39668819/article/details/115720713
14行为型设计模式—模板方法模式https://blog.csdn.net/qq_39668819/article/details/115774426
15行为型设计模式—策略模式https://blog.csdn.net/qq_39668819/article/details/115804292
16行为型设计模式—命令模式https://blog.csdn.net/qq_39668819/article/details/115877361
17行为型设计模式—责任链模式https://blog.csdn.net/qq_39668819/article/details/115981287
18行为型设计模式—状态模式https://blog.csdn.net/qq_39668819/article/details/116077215
19行为型设计模式—观察者模式https://blog.csdn.net/qq_39668819/article/details/116141223
20行为型设计模式—中介者模式https://blog.csdn.net/qq_39668819/article/details/116177694
21行为型设计模式—迭代器模式https://blog.csdn.net/qq_39668819/article/details/116213033
22行为型设计模式—访问者模式https://blog.csdn.net/qq_39668819/article/details/116246907
23行为型设计模式—备忘录模式https://blog.csdn.net/qq_39668819/article/details/116333844
24行为型设计模式—解释器模式https://blog.csdn.net/qq_39668819/article/details/116379466
命令模式

在现实生活中,我们可以会遇到这种情况:在路边烧烤摊吃烧烤时,人少的时候还好,人多的时候就有可能出现师傅弄错顾客的口味【要辣/不要辣】或 忘记顾客是否已给钱 或者弄错烤串的数量等等一系列问题;而在烧烤店中却少有这种情况,在烧烤店中服务员通常会把顾客的需求记录下来,将记录交给厨师处理,顾客也不必直接和厨师打交道;这种行为模式就是命令模式的体现。还比如看电视时我们可以通过遥控来控制频道切换,音量的调节;通过空调遥控控制空调的温度、风向、模式等等。

在软件开发系统中,“方法的请求者” 与 “方法的实现者” 之间经常存在紧密的耦合关系,这样我们如果需要对方法进行 “撤销”、“排队”、“重做”,“记录日志” 等处理时就很不方便了;为了将 “方法的请求者” 与 “方法的实现者” 解耦,我们可以使用命令模式。

模式的定义

命令模式 (Command),将一个请求封装为一个对象,使 “行为的请求者” 与 “行为的实现者” 责任分割开;两者之间通过命令对象进行沟通,这样方便了对请求排队或记录请求日志,以及支持可撤销的操作。

命令模式的优点:

  • 它能较容易地设计一个命令队列。
  • 在需要的情况下,可以较容易地将命令记入日志。
  • 允许接收请求的一方决定是否要否决请求。
  • 可以实现宏命令。命令模式可以与组合模式结合使用,将多个命令装配成一个组合命令,即宏命令。
  • 可以容易地实现对请求的撤销和重做。
  • 扩展性良好,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,且满足“开闭原则”。
  • 最关键的优点就是命令模式把 “行为的请求者” 与 “行为的实现者” 分割开,降低了对象间的耦合度。

缺点:

  • 由于每一个具体操作都需要设计一个具体命令类,可能产生大量具体的命令类,这会增加系统的复杂性。
模式的结构

命令模式的主要角色如下:

  • 抽象命令类角色(Command):声明了执行命令的接口,拥有执行命令抽象的方法。
  • 具体命令类角色(Concrete Command):实现类抽象命令类,拥有命令接收者对象,并通过调用接收者的方法来完成命令需要执行的操作。
  • 接收者角色(Receiver):执行命令功能相关的操作,是具体命令对象业务的真正执行者,包含具体的执行方法。
  • 调用者角色(Invoker):作为请求的调用者,通常拥有很多命令对象,并通过命令对象来执行相关的请求,通过命令对象访问接收者。

其 UML 图如下:

20210419222235466

模式的使用

这里我们以遥控器操作空调为例,演示命令模式的使用。

抽象命令类角色:Command 提供了一个执行命令的方法 execute()

具体命令类角色:该实例中共有4个具体命令类,PatternCommand 负责调节空调的模式【制冷、制热、抽湿、送风】,WindDirectionCommand 负责控制空调的风向【上下扫风、左右扫风】,TemperatureCommand 负责调节空调的温度【提高温度/降低温度】,TimingCommand 负责设置空调的定时开/关命令。

接收者角色:空调类 AirConditioner 负责所有空调相关的操作【温度调节、风向调节、定时任务、模式设置】的具体实现。

调用者角色:遥控类 RemoteControl 中持有多个具体命令,通过执行具体命令来实现客户端请求。

/**
* 接收者 - 空调类
*/
public class AirConditioner {

    /**
     * 最高温度
     */
    private int maxTemperature = 36;
    /**
     * 最低温度
     */
    private int minTemperature = 16;
    /**
     * 当前温度 - 默认26
     */
    private int temperature = 26;
    /**
     * 风向 - 默认上-下扫风
     */
    private String windDirection = "up_down";
    /**
     * 模式 - 默认制冷
     */
    private String pattern = "refrigeration";
    /**
     * 定时开启
     */
    private float timingOpen;
    /**
     * 定时关闭
     */
    private float timingOff;

    /**
     * 修改空调温度
     * @param offset
     * @return
     */
    public int updateTemperature(int offset) {
        int result = this.temperature + offset;
        if (result < minTemperature || result > maxTemperature) {
            System.out.println("温度不在有效范围【16 - 36】");
            return -1;
        }
        this.temperature = result;
        System.out.println("修改温度成功,现在空调温度为:" + this.temperature);
        return temperature;
    }

    /**
     * 修改空调风向
     * @param windDirection
     * @return
     */
    public String updateWindDirection(String windDirection) {
        this.windDirection = windDirection;
        System.out.println("修改风向成功,现在空调风向为:" + windDirection);
        return windDirection;
    }

    /**
     * 设置定时开
     * @param time
     * @return
     */
    public boolean setTimingOpen(float time) {
        if (time <= 0 || time > 24) {
            System.out.println("定时时间不在有效范围【> 0 且 <= 24】");
            return false;
        }
        this.timingOpen = time;
        System.out.println("设置空调定时开启成功,时间为 " + time + " 小时后开启");
        return true;
    }

    /**
     * 设置定时关
     * @param time
     * @return
     */
    public boolean setTimingOff(float time) {
        if (time <= 0 || time > 24) {
            System.out.println("定时时间不在有效范围【> 0 且 <= 24】");
            return false;
        }
        this.timingOpen = time;
        System.out.println("设置空调定时关闭成功,时间为 " + time + " 小时后关闭");
        return true;
    }

    /**
     * 修改空调模式
     * @param pattern
     * @return
     */
    public boolean updatePattern(String pattern) {
        this.pattern = pattern;
        System.out.println("修改空调模式成功,当前模式为:" + pattern);
        return true;
    }
}
/**
* 抽象命令类
*/
public interface Command {

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

/**
* 具体命令类 - 空调模式调节命令
*/
public class PatternCommand implements Command{

    /**
     * 空调对象
     */
    private AirConditioner airConditioner;
    /**
     * 空调模式
     */
    private String pattern;

    public PatternCommand(AirConditioner airConditioner, String pattern) {
        this.airConditioner = airConditioner;
        this.pattern = pattern;
    }

    @Override
    public void execute() {
        airConditioner.updatePattern(pattern);
    }
}

/**
* 具体命令类 - 空调风向调节命令
*/
public class WindDirectionCommand implements Command{

    /**
     * 空调对象
     */
    private AirConditioner airConditioner;
    /**
     * 风向
     */
    private String windDirection;

    public WindDirectionCommand(AirConditioner airConditioner, String windDirection) {
        this.airConditioner = airConditioner;
        this.windDirection = windDirection;
    }

    @Override
    public void execute() {
        airConditioner.updateWindDirection(windDirection);
    }
}

/**
* 具体命令类 - 空调温度调节命令
*/
public class TemperatureCommand implements Command{

    /**
     * 空调对象
     */
    private AirConditioner airConditioner;

    /**
     * 温度偏移量,正数为加,负数为减
     */
    private int offset;

    public TemperatureCommand(AirConditioner airConditioner, int offset) {
        this.airConditioner = airConditioner;
        this.offset = offset;
    }

    @Override
    public void execute() {
        airConditioner.updateTemperature(offset);
    }
}

/**
* 具体命令类 - 空调定时命令
*/
public class TimingCommand implements Command{

    /**
     * 空调对象
     */
    private AirConditioner airConditioner;
    /**
     * 类型:开启[open]/关闭[off]
     */
    private String type;
    /**
     * 时间
     */
    private float time;

    public TimingCommand(AirConditioner airConditioner, String type, float time) {
        this.airConditioner = airConditioner;
        this.type = type;
        this.time = time;
    }

    @Override
    public void execute() {
        if ("off".equals(type)) {
            airConditioner.setTimingOff(time);
        } else {
            airConditioner.setTimingOpen(time);
        }
    }
}
/**
* 调用者 - 遥控类
*/
public class RemoteControl {

    private List<Command> commands = new CopyOnWriteArrayList<>();

    /**
     * 添加命令
     * @param command
     */
    public void addCommand(Command command) {
        commands.add(command);
    }

    /**
     * 删除命令
     * @param command
     */
    public void removeCommand(Command command) {
        commands.remove(command);
    }

    /**
     * 全部执行
     */
    public void execute() {
        for (Command command : commands) {
            command.execute();
        }
    }
}

/**
* 命令模式测试类
*/
public class CommandTest {

    public static void main(String[] args) {
        AirConditioner airConditioner = new AirConditioner();

        // 温度 21,风向 上-下扫风,模式:制冷, 1小时候定时关闭空调
        Command temperatureCommand = new TemperatureCommand(airConditioner, -5);
        Command windDirectionCommand = new WindDirectionCommand(airConditioner, "up_down");
        PatternCommand patternCommand = new PatternCommand(airConditioner, "refrigeration");
        TimingCommand timingCommand = new TimingCommand(airConditioner, "off", 1);

        RemoteControl remoteControl = new RemoteControl();
        remoteControl.addCommand(temperatureCommand);
        remoteControl.addCommand(windDirectionCommand);
        remoteControl.addCommand(patternCommand);
        remoteControl.addCommand(timingCommand);
        //执行命令
        remoteControl.execute();
    }
}

运行程序,结果如下:

20210419223154593

小总结
  • 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开;调用者发出命令,接收者执行命令。
  • 每一个命令都是一个操作:调用者发出请求,要求执行一个操作;接收者收到请求,并执行操作。
  • 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
  • 命令模式将调用者和接收者独立开来,使得调用者不必知道接收者的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
  • 命令模式的关键在于引入了抽象命令接口,调用者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
模式的应用场景

当系统的某项操作具备命令语义,且命令实现不稳定(变化)时,可以通过命令模式解耦请求与实现。使用抽象命令接口使请求方的代码架构稳定,封装接收方具体命令的实现细节。接收方与抽象命令呈现弱耦合(内部方法无需一致),具备良好的扩展性。

  • 请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
  • 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以与 “备忘录模式” 配合使用,将命令对象存储起来,以备后续恢复。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值