设计模式 - 命令模式
一、引入
当你在玩电视遥控器时,你按下一个按钮,电视就会打开。你不需要了解电视是如何工作的,只需要知道按下按钮就能实现你想要的功能。命令模式就好像是一个遥控器,它帮助你将一个请求(比如打开电视)封装成一个对象,然后通过这个对象来执行请求,而无需了解具体的实现细节。
二、概念
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而使得可以参数化、队列化、记录日志或者撤销请求。
在命令模式中,命令对象包含了一个接收者和一组操作,它可以调用接收者的方法来完成特定的任务。
三、基本结构
- 命令接口(Command):定义了执行命令的接口。
- 具体命令(Concrete Command):实现了命令接口,包含了对接收者的引用和执行操作。
- 接收者(Receiver):负责执行命令的具体操作。
- 调用者(Invoker):负责调用命令并执行它。
- 客户端(Client):创建具体命令对象并配置它的接收者。
四、示例代码
假设我们有一个简单的遥控器,可以控制电视机的开关、音量调节和频道切换。我们可以使用命令模式来实现这个功能。
命令接口
/**
* 命令接口
*/
public interface Command {
void execute();
}
具体的命令:关闭电视、打开电视、调节音量
/**
* 关闭电视命令
*/
public class TurnOffCommand implements Command {
private Television television;
public TurnOffCommand(Television television) {
this.television = television;
}
@Override
public void execute() {
television.turnOff();
}
}
/**
* 打开电视命令
*/
public class TurnOnCommand implements Command {
private Television television;
public TurnOnCommand(Television television) {
this.television = television;
}
@Override
public void execute() {
television.turnOn();
}
}
/**
* 调节音量命令
*/
public class AdjustVolumeCommand implements Command {
private Television television;
private Integer volume;
public AdjustVolumeCommand(Television television, Integer volume) {
this.television = television;
this.volume = volume;
}
@Override
public void execute() {
television.adjustVolume(volume);
}
}
接受者
/**
* 接受者
*/
public class Television {
public void turnOn() {
System.out.println("打开电视机");
}
public void turnOff() {
System.out.println("关闭电视机");
}
public void adjustVolume(int volume) {
System.out.println("调节音量 " + volume);
}
}
调用者
/**
* 调用者
*/
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
客户端
public class Client {
public static void main(String[] args) {
Television television = new Television();
TurnOnCommand turnOnCommand = new TurnOnCommand(television);
TurnOffCommand turnOffCommand = new TurnOffCommand(television);
AdjustVolumeCommand adjustVolumeCommand = new AdjustVolumeCommand(television, 20);
RemoteControl remoteControl = new RemoteControl();
//调用打开电视命令
remoteControl.setCommand(turnOnCommand);
remoteControl.pressButton();
//调用关闭电视命令
remoteControl.setCommand(turnOffCommand);
remoteControl.pressButton();
//调用调节音量命令
remoteControl.setCommand(adjustVolumeCommand);
remoteControl.pressButton();
}
}
五、能干什么
- 封装操作:将一个请求封装成一个对象,从而使得可以参数化和传递请求,以及支持撤销和重做操作。
- 解耦调用者和接收者:调用者无需知道接收者的具体信息,只需要通过命令对象来执行请求。
- 支持撤销和重做:由于命令对象可以记录操作历史,可以实现撤销和重做功能。
- 支持事务:可以将多个操作封装成一个命令对象,从而实现事务。
- 支持队列请求:可以将命令对象放入队列中,实现异步处理请求。
- 支持日志和记录:可以记录所有执行的命令,用于日志记录或者回放。
六、总结
优点:
- 降低系统耦合度:命令模式将请求发送者和接收者解耦,使得系统更加灵活,可以方便地扩展和维护。
- 支持撤销和重做:由于命令对象可以记录操作历史,可以实现撤销和重做功能。
- 支持事务处理:可以将多个操作封装成一个命令对象,从而实现事务处理。
- 支持队列请求:可以将命令对象放入队列中,实现异步处理请求。
- 支持日志和记录:可以记录所有执行的命令,用于日志记录或者回放。
- 容易扩展新的命令:可以通过添加新的具体命令类来扩展系统的功能。
缺点:
- 会增加类的数量:每个具体命令类都需要一个单独的类来实现,可能会增加系统的复杂性。
- 可能会导致过多的具体命令类:如果系统中有大量的具体命令类,可能会导致类的数量过多,不利于维护。
- 可能会增加系统开销:每个具体命令类都需要一个单独的对象来维护,可能会增加系统的内存开销。