Java设计模式 十七 命令模式 (Command Pattern)

命令模式 (Command Pattern)

命令模式是一种行为型设计模式,它将请求(或操作)封装成一个对象,从而使得用户可以通过不同的请求执行不同的操作,甚至支持撤销操作。命令模式的关键在于:将请求的发送者和请求的接收者解耦,并将请求封装成一个对象。这样,发送者只需要将请求发送给一个命令对象,而无需关心请求的具体实现和执行过程。


1. 命令模式的组成

命令模式通常包含以下几个角色:

  • Command(命令接口):定义了执行命令的接口,通常有一个execute()方法,所有具体的命令类都需要实现这个接口。
  • ConcreteCommand(具体命令类):实现了Command接口,并将具体的请求委托给接收者对象。
  • Invoker(调用者):请求的发送者,持有命令对象并触发命令的执行。
  • Receiver(接收者):实际执行命令的对象,它负责执行具体的操作。
  • Client(客户端):负责创建具体命令对象并将其传递给调用者。

2. 命令模式的工作流程

  1. 客户端创建一个具体命令对象(ConcreteCommand),并设置相应的接收者。
  2. 客户端将命令对象传递给调用者(Invoker)。
  3. 调用者通过调用命令对象的execute()方法来执行请求。
  4. 命令对象将请求委托给接收者对象,由接收者完成实际的操作。

3. 命令模式的实现

场景示例:遥控器操作

假设我们有一个遥控器,它能够控制多个家电设备(如灯、电视、空调等)。我们希望通过命令模式实现每个设备的开/关操作,并且支持撤销操作。


1) 定义命令接口

命令接口定义了一个execute()方法,所有具体命令类都要实现这个方法。

// 命令接口
public interface Command {
    void execute();
    void undo();  // 撤销操作
}

2) 定义具体命令类

具体命令类实现了命令接口,并调用接收者(家电)的实际操作方法。

// 开灯命令
public class LightOnCommand implements Command {
    private Light light;

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

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

    @Override
    public void undo() {
        light.turnOff();
    }
}

// 关灯命令
public class LightOffCommand implements Command {
    private Light light;

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

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

    @Override
    public void undo() {
        light.turnOn();
    }
}

3) 定义接收者类

接收者类是真正执行命令的类(例如,家电设备)。它包含具体的业务逻辑。

// 灯类(接收者)
public class Light {
    public void turnOn() {
        System.out.println("The light is ON");
    }

    public void turnOff() {
        System.out.println("The light is OFF");
    }
}

4) 定义调用者类

调用者类持有命令对象,并通过execute()方法来请求执行操作。

// 遥控器(调用者)
public class RemoteControl {
    private Command command;

    // 设置命令
    public void setCommand(Command command) {
        this.command = command;
    }

    // 执行命令
    public void pressButton() {
        command.execute();
    }

    // 撤销操作
    public void pressUndoButton() {
        command.undo();
    }
}

5) 客户端代码

客户端代码创建了遥控器、命令对象和接收者对象,并将命令对象设置到遥控器中。

public class Client {
    public static void main(String[] args) {
        // 创建接收者
        Light livingRoomLight = new Light();
        
        // 创建命令对象
        Command lightOn = new LightOnCommand(livingRoomLight);
        Command lightOff = new LightOffCommand(livingRoomLight);

        // 创建遥控器(调用者)
        RemoteControl remoteControl = new RemoteControl();
        
        // 执行开灯命令
        remoteControl.setCommand(lightOn);
        remoteControl.pressButton();  // 输出:The light is ON
        
        // 执行关灯命令
        remoteControl.setCommand(lightOff);
        remoteControl.pressButton();  // 输出:The light is OFF
        
        // 撤销上一个命令(开灯)
        remoteControl.pressUndoButton();  // 输出:The light is ON
    }
}

运行结果:
The light is ON
The light is OFF
The light is ON

4. 命令模式的优点

  1. 解耦发送者和接收者: 发送请求的类(调用者)与接收请求的类(接收者)解耦,发送者无需知道请求的执行细节。
  2. 支持撤销操作: 每个命令对象都可以定义撤销操作(undo()),允许在需要时撤销操作。
  3. 扩展性: 可以轻松添加新的命令,只需要创建新的命令类而不需要修改现有代码,符合开闭原则。
  4. 组合命令: 可以通过组合多个命令来实现更复杂的操作,如“宏命令”。
  5. 事务性操作: 命令模式可以用于将操作封装成单独的事务,并在系统中进行管理。

5. 命令模式的缺点

  1. 类的数量增加: 每一个新的命令都需要一个新的命令类,这可能导致类的数量急剧增加,增加系统的复杂度。
  2. 实现复杂: 对于较简单的操作,使用命令模式可能会显得过于复杂,导致不必要的设计开销。

6. 命令模式的应用场景

  1. GUI系统中的操作: 如按钮点击事件、菜单操作等,可以使用命令模式来封装每个按钮的动作。每个按钮对应一个命令对象,点击时执行相应的命令。
  2. 任务队列: 命令模式适用于任务调度系统,每个任务可以封装成一个命令,系统可以按照需要顺序执行或撤销任务。
  3. 宏命令: 需要将多个命令组合成一个大的操作时,可以使用命令模式组合多个小命令。
  4. 实现撤销/重做操作: 例如,文本编辑器中的撤销/重做功能,可以利用命令模式管理操作的历史记录。

7. 总结

命令模式通过将请求封装成对象,解耦了请求的发送者和接收者,提供了灵活的执行、撤销和组合命令的能力。它在需要解耦请求和执行的场景中非常有用,尤其适用于GUI系统、任务调度、宏命令等应用场景。虽然命令模式可能增加系统的复杂度,但它在结构上更具可扩展性和灵活性,非常适合处理复杂的操作逻辑。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十方来财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值