【设计模式】命令模式

简介: 读完单例模式,接着品命令模式,命令模式在工程实践中有应用,如MVC框架中使用了命令模式,还有日志系统(从异常中恢复)和事务系统都可以使用命令模式,命令模式可以解耦命令请求者和命令执行者,下面开始学习命令模式。

一、前言


  读完单例模式,接着品命令模式,命令模式在工程实践中有应用,如MVC框架中使用了命令模式,还有日志系统(从异常中恢复)和事务系统都可以使用命令模式,命令模式可以解耦命令请求者和命令执行者,下面开始学习命令模式。


二、命令模式定义


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


  从定义可以看出,命令模式核心的概念就是讲请求封装成为对象,这样,对象可以被传递,从而解耦请求者和执行者。


  命令模式的类图如下


616953-20160613103646323-1784848450.png

说明:对于类图说明如下


  ① Client负责创建一个ConcreteCommand,并设置接受者。


  ② Invoker持有一个命令对象,并在某个时间点调用命令对象的execute方法,将请求付诸实行。


  ③ Command为所有命令声明了一个接口,调用命令对象的execute方法,就可以让接受者进行相关的动作,这个接口也具备一个undo方法。


  ④ ConcreteCommand定义了动作和接受者之间的绑定关系,调用者只要调用execute方法就可以发出请求,然后由ConcreteCommand调用接受者的一个或多个动作。


  ⑤ Receiver为接受者,实现请求具体的动作,任何类都可以当接受者。

三、示例说明


  设想如下场景,家里的电器都通过一个遥控器来控制,按下按钮即可控制电器的开关,并且只要在遥控的相关插口插入对应的电器模块,即可控制相应的电器,即可很方便的进行替换。


  3.1 v1.0


  Command  

package com.hust.grid.leesf.command;
interface Command {
    void execute();
    void undo();
}

  LightOnCommand

package com.hust.grid.leesf.command;
public class LightOnCommand implements Command {
    private Receiver light;
    public LightOnCommand(Receiver receiver) {
        this.light = receiver;
    }
    @Override
    public void execute() {
        light.on();
    }
    @Override
    public void undo() {
        light.off();
    }
}

 LightOffCommand

package com.hust.grid.leesf.command;
public class LightOffCommand implements Command {
    private Receiver light;
    public LightOffCommand(Receiver receiver) {
        light = receiver;
    }
    @Override
    public void execute() {
        light.off();
    }
    @Override
    public void undo() {
        light.on();
    }
}

  CeilingFanOnCommand

package com.hust.grid.leesf.command;
public class CeilingFanOnCommand implements Command {
    private Receiver ceilingFan;
    public CeilingFanOnCommand(Receiver receiver) {
        ceilingFan = receiver;
    }
    @Override
    public void execute() {
        ceilingFan.on();
    }
    @Override
    public void undo() {
        ceilingFan.off();
    }
}

  CeilingFanOffCommand

package com.hust.grid.leesf.command;
public class CeilingFanOffCommand implements Command {
    private Receiver ceilingFan;
    public CeilingFanOffCommand(Receiver receiver) {
        ceilingFan = receiver;
    }
    @Override
    public void execute() {
        ceilingFan.off();
    }
    @Override
    public void undo() {
        ceilingFan.on();
    }
}

 Receiver

package com.hust.grid.leesf.command;
public abstract class Receiver {
    protected String name;
    public Receiver(String name) {
        this.name = name;
    }
    public void on() {
        System.out.println(this.name + " is on");
    }
    public void off() {
        System.out.println(this.name + " is off");
    }
}

 Light

package com.hust.grid.leesf.command;
public class Light extends Receiver {
    public Light(String name) {
        super(name);
    }
}

 CeilingFan

package com.hust.grid.leesf.command;
public class CeilingFan extends Receiver {
    public CeilingFan(String name) {
        super(name);
    }
}

 RemoteController

package com.hust.grid.leesf.command;
public class RemoteController {
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;
    public RemoteController(int slotSize) {
        onCommands = new Command[slotSize];
        offCommands = new Command[slotSize];
    }
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    public void onButtonWasPushed(int slot) {
        undoCommand = onCommands[slot];
        onCommands[slot].execute();
    }
    public void offButtonWasPushed(int slot) {
        undoCommand = offCommands[slot];
        offCommands[slot].execute();
    }
    public void undoButtonWasPushed() {
        undoCommand.undo();
    }
}

 Main(用于测试)

package com.hust.grid.leesf.command;
public class Main {
    public static void main(String[] args) {
        // 遥控器
        RemoteController remoteController = new RemoteController(3);
        Light livingRoomLight = new Light("LivingRoomLight");
        Light kitchenLight = new Light("KitchenLight");
        CeilingFan ceilingFan = new CeilingFan("CeilingFan");
        LightOnCommand livingRoomLightOnCommand = new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOffCommand = new LightOffCommand(livingRoomLight);
        LightOnCommand kitchenLightOnCommand = new LightOnCommand(kitchenLight);
        LightOnCommand kitchenLightOffCommand = new LightOnCommand(kitchenLight);
        CeilingFanOnCommand ceilingFanOnCommand = new CeilingFanOnCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOffCommand = new CeilingFanOffCommand(ceilingFan);
        remoteController.setCommand(0, livingRoomLightOnCommand, livingRoomLightOffCommand);
        remoteController.setCommand(1, kitchenLightOnCommand, kitchenLightOffCommand);
        remoteController.setCommand(2, ceilingFanOnCommand, ceilingFanOffCommand);
        // 模拟遥控按下按钮
        remoteController.onButtonWasPushed(0);        
        remoteController.onButtonWasPushed(1);
        remoteController.onButtonWasPushed(2);
        remoteController.offButtonWasPushed(2);
        // 撤销操作
        remoteController.undoButtonWasPushed();
    }
}

 运行结果

LivingRoomLight is on
KitchenLight is on
CeilingFan is on
CeilingFan is off
CeilingFan is on

  说明:使用了命令模式,一切都运行良好,并且可进行撤销操作。


  若需要添加这样的功能,当按下按钮时,指定的所有电器都开或者关闭,即宏命令。

  

3.2 v2.0


  添加宏命令,即一次性可以执行多个命令


  MacroCommand

package com.hust.grid.leesf.command;
public class MacroCommand implements Command {
    private Command[] commands;
    public MacroCommand(Command[] commands) {
        this.commands = commands;
    }
    @Override
    public void execute() {
        for (int i = 0; i < commands.length; i++) {
            commands[i].execute();
        }
    }
    @Override
    public void undo() {
        for (int i = 0; i < commands.length; i++) {
            commands[i].undo();
        }
    }

 Main(用作测试)

package com.hust.grid.leesf.command;
public class Main {
    public static void main(String[] args) {
        // 遥控器
        RemoteController remoteController = new RemoteController(4);
        Light livingRoomLight = new Light("LivingRoomLight");
        Light kitchenLight = new Light("KitchenLight");
        CeilingFan ceilingFan = new CeilingFan("CeilingFan");
        LightOnCommand livingRoomLightOnCommand = new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOffCommand = new LightOffCommand(livingRoomLight);
        LightOnCommand kitchenLightOnCommand = new LightOnCommand(kitchenLight);
        LightOnCommand kitchenLightOffCommand = new LightOnCommand(kitchenLight);
        CeilingFanOnCommand ceilingFanOnCommand = new CeilingFanOnCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOffCommand = new CeilingFanOffCommand(ceilingFan);
        Command[] partyOn = {livingRoomLightOnCommand, kitchenLightOnCommand, ceilingFanOnCommand};
        Command[] partyOff = {livingRoomLightOffCommand, kitchenLightOffCommand, ceilingFanOffCommand};
        MacroCommand macroOnCommand = new MacroCommand(partyOn);
        MacroCommand macroOffCommand = new MacroCommand(partyOff);
        remoteController.setCommand(0, livingRoomLightOnCommand, livingRoomLightOffCommand);
        remoteController.setCommand(1, kitchenLightOnCommand, kitchenLightOffCommand);
        remoteController.setCommand(2, ceilingFanOnCommand, ceilingFanOffCommand);
        remoteController.setCommand(3, macroOnCommand, macroOffCommand);
        // 模拟遥控按下按钮
        remoteController.onButtonWasPushed(3);
        // 撤销操作
        remoteController.undoButtonWasPushed();
    }
}

  运行结果

LivingRoomLight is on
KitchenLight is on
CeilingFan is on
LivingRoomLight is off
KitchenLight is off
CeilingFan is off

说明:可以看到,调用了宏命令后,一次性执行了多条命令,并且执行撤消后,会恢复到之前的状态。


  命令模式的要点如下:


  ① 命令模式将发出的请求的对象和执行请求的对象解耦


  ② 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或一组动作。


  ③ 调用者通过调用命令对象的execute方法发出请求,这会使得接受者的动作被调用。


  ④ 调用者可以接受命令当做参数,甚至在运行时动态地进行。


目录
相关文章
|
7月前
|
设计模式 UED
二十三种设计模式:解锁软件开发的神器:命令模式与撤销重做功能
二十三种设计模式:解锁软件开发的神器:命令模式与撤销重做功能
175 0
|
3月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
4月前
|
设计模式 存储 Java
【十二】设计模式~~~行为型模式~~~命令模式(Java)
文章详细介绍了命令模式(Command Pattern),这是一种对象行为型模式,用于将请求封装成对象,实现请求发送者与接收者的解耦,从而降低系统耦合度、提高灵活性,并支持命令的排队、记录、撤销和恢复操作。通过案例分析、结构图、时序图和代码示例,文章展示了命令模式的组成部分、实现方式和应用场景,并讨论了其优点、缺点和适用情况。
|
5月前
|
设计模式 JavaScript API
js设计模式【详解】—— 命令模式
js设计模式【详解】—— 命令模式
47 6
|
6月前
|
设计模式
命令模式-大话设计模式
命令模式-大话设计模式
|
6月前
|
设计模式 Java uml
必知的技术知识:JAVA【设计模式】命令模式
必知的技术知识:JAVA【设计模式】命令模式
30 0
|
6月前
|
设计模式 Java
Java设计模式之命令模式详解
Java设计模式之命令模式详解
|
6月前
|
设计模式
设计模式之命令模式
设计模式之命令模式
|
7月前
|
设计模式 Java 调度
【设计模式系列笔记】命令模式
命令模式是一种行为设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或日志请求参数化客户端对象,同时支持撤销操作。
72 1
|
7月前
|
设计模式 Java 调度
小谈设计模式(24)—命令模式
小谈设计模式(24)—命令模式