# 命令模式

本文作者:程序员飞云

本站地址:https://www.flycode.icu (opens new window)

# 1. 什么是命令模式?

命令模式(Command): 将一个请求分装成一个对象,从而可以使用不同的请求对客户进行参数化;对于请求排队或者请求日志,以及支持可撤销的操作。

主要是将客户端和执行请求的对象解耦。

举个常见的两个例子

一个是我们生活中使用遥控器来控制电视,我们控制遥控器(相当于客户端),点击遥控按钮*(命令)来控制电视( 执行请求的对象),即使遥控器坏了也没用影响,可以使用新的遥控器,但是电视坏了,遥控器就没用了。

另一个是去烧烤店点单,我们告诉服务员,通过点单命令来告诉烧烤师傅 要考什么肉,而这个服务员是谁我们不关心,这个服务员忙,我们可以找另一个服务员。( 这个例子不大适合小的烧烤店,一般老板一个人就包了2个人的工作)

# 2. 优点

  1. 可以容易设计一个命令队列
  2. 容易的将一些命令写入日志
  3. 允许接收请求的一方决定是否拒绝请求
  4. 容易实现对请求的撤销和重做
  5. 加入了新的命令类不影响其他的类 6解耦了请求者以及接收者,系统更加灵活

# 3. 使用场景

  1. 操作多种的复杂操作,比如排队,请求日志,记录操作,撤消重做等等
  2. 系统需要增加新的命令不影响之前的功能,或者处理复杂的组合命令

# 4. 案例一:遥控器--电视

# 1. 接受者: 电视

最终执行命令的对象,知道具体的相关操作

这里就设置一个电视的电视名字字段,有两个功能开启电视,关闭电视

/**
 * 接收者,电视设备
 */
public class Device {
    private String name;

    public Device(String name) {
        this.name = name;
    }

    public void on() {
        System.out.println("开启: " + this.name);
    }

    public void off() {
        System.out.println("关闭: " + this.name);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2. 命令Command

相当于总的遥控器按钮制定的规范,这个命令才是控制电视开关的核心

public interface Command {
    void execute(); // 执行命令
}
1
2
3

# 3. 开启按钮的命令

/**
 * 开启命令
 */
public class TurnOnCommand implements Command {
    private Device device;

    public TurnOnCommand(Device device) {
        this.device = device;
    }


    @Override
    public void execute() {
        device.on();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 4. 关闭按钮的命令

/**
 * 关闭命令
 */
public class TurnOffCommand implements Command {
    private Device device;

    public TurnOffCommand(Device device) {
        this.device = device;
    }

    @Override
    public void execute() {
        device.off();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5. 调用者

遥控器点击按钮后,如果是开,就是执行的TurnOnCommand命令,然后命令执行里面的execute

/**
 * 遥控器
 */
public class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command=command;
    }

    /**
     *  按下按钮
     */
    public void buttonWasPressed() {
        command.execute();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 6. 客户端

用户操作,点击遥控器

需要对应的电视,按钮,操作。

public class Client {
    public static void main(String[] args) {
        // 电视
        Device device = new Device("TCL");

        // 遥控器
        RemoteControl remoteControl = new RemoteControl();

        // 对电视发布命令
        TurnOnCommand turnOnCommand = new TurnOnCommand(device);

        // 执行命令
        remoteControl.setCommand(turnOnCommand);

        // 响应结果
        remoteControl.buttonWasPressed();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 7. 进阶 :记录历史

这个操作其实还算简单,就是使用一个集合来存放对应的命令

/**
 * 遥控器
 */
public class RemoteControl {
    private Command command;

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

    public void setCommand(Command command) {
        this.commands.add(command);
        this.command = command;
    }

    /**
     * 按下按钮
     */
    public void buttonWasPressed() {
        command.execute();
    }

    public void buttonHistory() {
        for (Command command : commands) {
            command.execute();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 8. 进阶:显示一系列操作

public class Client {
    public static void main(String[] args) {
        // 电视
        Device device = new Device("TCL");
        // 遥控器
        RemoteControl remoteControl = new RemoteControl();
        // 对电视发布命令
        TurnOnCommand turnOnCommand = new TurnOnCommand(device);
        TurnOffCommand turnOffCommand = new TurnOffCommand(device);
        TurnOnCommand turnOnCommand2 = new TurnOnCommand(device);
        // 执行命令
        remoteControl.setCommand(turnOnCommand);
        remoteControl.setCommand(turnOffCommand);
        remoteControl.setCommand(turnOnCommand2);
        // 响应结果
        remoteControl.buttonWasPressed();
        System.out.println("------------");
        // 操作历史
        remoteControl.buttonHistory();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 9. 运行截图

image-20231230173609139

# 10. uml图

# 5. 案例二:烤肉串师傅—服务员

# 1. 接收者: 烤肉串师傅

具有考鸡翅和考羊肉的功能

/**
 * 烤肉师傅
 */
public class Barbecuer {

    public void bakeMutton() {
        System.out.println("烤羊肉串");
    }
    
    public void bakeChickenWing() {
        System.out.println("烤鸡翅");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2. 命令Command

执行命令

public interface Command {
    void execute(); // 执行命令
}
1
2
3

# 3. 具体命令

烤羊肉命令

/**
 * 烤羊肉命令
 */
public class BakeMuttonCommand implements Command {
    private Barbecuer barbecuer;

    public BakeMuttonCommand(Barbecuer barbecuer) {
        this.barbecuer = barbecuer;
    }

    @Override
    public void execute() {
        barbecuer.bakeMutton();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

烤鸡翅命令

/**
 * 烤鸡翅命令
 */
public class BakeChickenWingCommand implements Command {
    private Barbecuer barbecuer;

    public BakeChickenWingCommand(Barbecuer barbecuer) {
        this.barbecuer = barbecuer;
    }

    @Override
    public void execute() {
        barbecuer.bakeChickenWing();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 4. 调用者–服务员

服务员发送相关的命令

/**
 * 服务员
 */
public class Waiter {
    //持有命令对象
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void action() {
        command.execute();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5. 客户端–用户

public class Client {
    public static void main(String[] args) {
        // 烤肉师傅
        Barbecuer barbecuer = new Barbecuer();

        // 服务员
        Waiter waiter = new Waiter();

        // 点菜命令
        BakeChickenWingCommand bakeChickenWingCommand = new BakeChickenWingCommand(barbecuer);

        // 服务员接受命令
        waiter.setCommand(bakeChickenWingCommand);

        // 反馈
        waiter.action();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

如果想要实现记录历史可以仿照前面的,还可以实现移除订单等等相关操作。

最近更新: 1/14/2025, 1:13:36 AM
飞云编程   |