文章目录
- 命令模式 (Command Pattern)
- 原理
- 优点
- 缺点
- 示例代码
- 场景描述
- 1. 定义命令接口
- 2. 定义具体命令类(实现命令接口)
- 3. 定义接收者类(设备)
- 4. 定义遥控器(调用者)
- 5. 客户端代码
- 输出结果
- UML 类图
- 使用场景
- 扩展与优化
- 小结
命令模式 (Command Pattern)
命令模式是一种 行为型设计模式,用于将请求(命令)封装成对象,从而使得用户可以通过不同的请求来执行不同的操作。这使得请求发送者与接收者解耦,允许通过不同的方式来控制请求的执行,比如队列、日志、撤销、恢复等。
原理
-
核心思想:
- 将请求封装为一个对象,通过对象传递请求,以解耦发送请求的对象和执行请求的对象。
- 每个命令都将一个特定的操作封装成一个对象,发送者不需要知道命令如何执行,只需要调用命令的执行方法。
-
参与角色:
- Command(命令接口):
- 定义执行命令的接口。
- ConcreteCommand(具体命令):
- 实现命令接口,调用接收者的相应操作。
- Invoker(调用者):
- 负责调用命令对象来执行请求,通常是客户端发起请求的地方。
- Receiver(接收者):
- 执行与请求相关的实际操作,具体的业务逻辑由接收者来实现。
- Client(客户端):
- 创建具体命令对象,并设置接收者。
- Invoker:
- 向命令对象发送请求。
- Command(命令接口):
优点
- 解耦请求发送者与接收者:
- 发送请求的对象与执行请求的对象之间没有直接依赖关系。
- 支持撤销操作:
- 通过命令对象,可以很方便地支持撤销和恢复操作。
- 可以组合命令:
- 命令模式支持宏命令,可以将多个命令组合成一个更复杂的命令对象。
- 扩展性强:
- 可以增加新的命令,而不需要修改客户端代码,符合开闭原则。
缺点
- 增加类的数量:
- 每个命令都需要创建一个类,可能导致类的数量增加。
- 复杂度提高:
- 对于一些简单的请求,使用命令模式可能会导致设计过于复杂。
示例代码
场景描述
假设我们有一个遥控器可以控制家庭设备,如灯、风扇。我们希望通过命令模式来解耦遥控器与设备的操作。
1. 定义命令接口
// 命令接口
public interface Command {void execute();
}
2. 定义具体命令类(实现命令接口)
// 打开灯的命令
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}// 关闭灯的命令
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}// 开启风扇的命令
public class FanOnCommand implements Command {private Fan fan;public FanOnCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.turnOn();}
}// 关闭风扇的命令
public class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.turnOff();}
}
3. 定义接收者类(设备)
// 灯类
public class Light {public void turnOn() {System.out.println("The light is ON");}public void turnOff() {System.out.println("The light is OFF");}
}// 风扇类
public class Fan {public void turnOn() {System.out.println("The fan is ON");}public void turnOff() {System.out.println("The fan is OFF");}
}
4. 定义遥控器(调用者)
// 遥控器类
public class RemoteControl {private Command slot;public void setCommand(Command command) {slot = command;}public void pressButton() {slot.execute();}
}
5. 客户端代码
public class CommandPatternExample {public static void main(String[] args) {// 创建设备Light light = new Light();Fan fan = new Fan();// 创建命令Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);Command fanOn = new FanOnCommand(fan);Command fanOff = new FanOffCommand(fan);// 创建遥控器并设置命令RemoteControl remote = new RemoteControl();// 按下按钮打开灯remote.setCommand(lightOn);remote.pressButton();// 按下按钮关闭灯remote.setCommand(lightOff);remote.pressButton();// 按下按钮开启风扇remote.setCommand(fanOn);remote.pressButton();// 按下按钮关闭风扇remote.setCommand(fanOff);remote.pressButton();}
}
输出结果
The light is ON
The light is OFF
The fan is ON
The fan is OFF
UML 类图
+------------------+
| Command |
+------------------+
| + execute() |
+------------------+^|+---------------+ +---------------+ +----------------+| LightOnCommand| | LightOffCommand| | FanOnCommand |+---------------+ +----------------+ +----------------+| - light: Light| | - light: Light | | - fan: Fan || + execute() | | + execute() | | + execute() |+---------------+ +----------------+ +----------------+^|+------------------+ +------------------+| Light | | Fan |+------------------+ +------------------+| + turnOn() | | + turnOn() || + turnOff() | | + turnOff() |+------------------+ +------------------+^|+--------------+ | RemoteControl|+--------------+| - slot: Command|| + setCommand() || + pressButton()|+--------------+
使用场景
- UI界面按钮处理:
- 在图形界面中,可以通过按钮触发命令执行,例如开关按钮、调节音量、播放视频等。
- 任务调度:
- 在任务调度系统中,可以将任务封装成命令对象并进行调度,支持操作的撤销和恢复。
- 菜单操作:
- 在菜单系统中,每个菜单项都可以被封装为一个命令,通过命令对象来执行不同的功能。
- 事务管理:
- 将所有操作封装成命令对象,支持事务的提交和回滚。
扩展与优化
-
命令组合:
- 可以将多个命令对象组合成一个宏命令,实现批量操作。例如,可以创建一个
MacroCommand
类,将多个命令对象组合在一起一次性执行。
- 可以将多个命令对象组合成一个宏命令,实现批量操作。例如,可以创建一个
-
支持撤销操作:
- 可以扩展命令接口,加入
undo()
方法,实现操作的撤销功能。每个具体命令类可以实现撤销操作,允许用户恢复到之前的状态。
- 可以扩展命令接口,加入
-
命令历史:
- 通过维护一个命令历史列表,可以实现命令的撤销与恢复,或者将命令队列保存为日志,支持后期回放。
小结
- 命令模式通过将请求封装成对象,允许在不同的时间和环境中进行请求的传递和执行。
- 解耦了请求的发送者与接收者,使得系统更加灵活且易于扩展。
- 适用于需要对请求进行队列、撤销、恢复、日志等操作的场景。