设计模式——(7)命令模式

第七章 命令模式

1.1 引言

为了介绍命令模式,引入如下场景:

设计一个家电自动化遥控器的API。这个遥控器具有七个可编程的插槽(每个都可以指定到一个不同的家电装置),每个插槽都有对应的开关按钮,这个遥控器还具备一个整体的撤销按钮。遥控器的硬件结构如下图所示。

请添加图片描述

遥控器对象与家电装置的关系?

当遥控器对象的开关按钮被按下,对应的家电装置会被操控,因此,在逻辑上,遥控器对象应关联具体的家电装置。

而对应的家电装置是变化的,可能新增、减少和更换,当遥控器对象操作这些家电装置的逻辑代码是变化的。

当遥控器对象的开关按钮被按下,如果遥控中的控制逻辑代码的设计如下:

if slot1 == Litht, 
then light on(),
else if slot1 == Hottub 
then hottob.jetsOn().

这样的设计,遥控器对象和具体的家电对象具有严重的耦合性!!!

因此,需要将遥控器对象从具体的家电对象中解耦。这里的遥控器对象可抽象称“动作的请求者”,而家电对象可抽象称“动作的执行者”,也就是说,需要将动作的请求者从动作的执行者中解耦。

前面不是说过当按钮按下,遥控器必须把电灯打开?这怎么可能解耦?

用“命令对象”可以办到!利用命令对象,把请求封装成一个特定的对象。所以如果对每个按钮都存储一个命令对象,那么当按钮被按下的时候,就可以请命令对象做相关的工作。遥控器并不需要知道工作的内容是什么,只要有个命令对象能和正确的对象沟通,把事情完成就可以了。由此实现动作的请求者与动作的执行者的解耦。

1.2 使用命令模式

首先定义命令对象的接口:Command 接口

package headfirst.designpatterns.command.simpleremote;

public interface Command {

    void execute();
}

实现一个打开电灯的命令:LightOnCommand

package headfirst.designpatterns.command.simpleremote;

public class LightOnCommand implements Command{
    
    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

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

实现一个简单的遥控器对象:SimpleRemoteControl 类,遥控器对象与电灯装置实现了解耦。

package headfirst.designpatterns.command.simpleremote;

public class SimpleRemoteControl {

    Command slot;

    public SimpleRemoteControl() {
    }

    public void setSlot(Command slot) {
        this.slot = slot;
    }

    public void buttonWasPressed(){
        slot.execute();
    }
}

再实现一个 GarageDoorOpenCommand 命令对象。

package headfirst.designpatterns.command.simpleremote; 

public class GarageDoorOpenCommand implements Command {

    GarageDoor garageDoor;

    public GarageDoorOpenCommand(GarageDoor garageDoor) {
        this.garageDoor = garageDoor;
    }

    @Override
    public void execute() {
        garageDoor.up();
    }
}

测试:RemoteControlTest 类

package headfirst.designpatterns.command.simpleremote;

public class RemoteControlTest {
    public static void main(String[] args) {
        SimpleRemoteControl remoteControl = new SimpleRemoteControl();
        LightOnCommand lightOnCommand = new LightOnCommand(new Light());
        remoteControl.setSlot(lightOnCommand);
        remoteControl.buttonWasPressed();
        
        GarageDoorOpenCommand garageDoorOpenCommand = new GarageDoorOpenCommand(new GarageDoor());
        // 重新设置遥控器的命令对象,lightOnCommand —> garageDoorOpenCommand.
        remoteControl.setSlot(garageDoorOpenCommand);
        remoteControl.buttonWasPressed();
    }
}

输出:

Light is on
Garage Door is Open

1.3 定义命令模式

命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持撤销的操作。

如何理解使用不同的请求来参数化其他对象呢?

这里的命令对象是LightOnCommand和GarageDoorOpenCommand,遥控器对象的插槽 Command slot,可通过这些命令对象赋值,也就是说,一个动作请求者可用不同的命令对象作参数,遥控器的插槽根本不在乎所拥有的是什么命令对象,只要该命令实现了Command接口就可以了。

命令模式的类图如下:

请添加图片描述

  • Client 为测试类 Test,
  • Receiver 是具体的家电装置 Light 和 GarageDoor,
  • Invoker 是遥控器 SimpleRemoteControl,
  • ConcreteCommand 是具体的命令对象。

命令模式通过 Command 接口和命令对象 ConcreteCommand ,实现了 Invoker 与 Receiver 的解耦。

参考

[1] Freeman E. Head First 设计模式[M] 中国电力出版社.
[2] 菜鸟教程.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值