命令模式(Command Pattern)又称为行动(Action)模式或交易(Transaction)模式。
命令模式的英文定义是:
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
意思是:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
简单来说,命令模式就是将发送者、接收者和调用命令封装成对象,客户端调用的时候可以选择不同的对象,从而实现发送者和接收者的完全解耦。
命令模式包含如下角色:
角色关系类图如下:
// 接收者
class Receiver {
public void doSomething() {
System.out.println("执行业务逻辑");
}
}
// 命令接口
interface Command {
void execute();
}
// 具体命令类
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
this.receiver.doSomething();
}
}
// 请求者类
class Invoker {
// 持有命令对象
private Command command;
public Invoker(Command command) {
this.command = command;
}
// 请求方法
public void action() {
this.command.execute();
}
}
// 客户端
class Client {
public static void main(String[] args) {
// 创建接收者
Receiver receiver = new Receiver();
// 创建命令对象,设定接收者
Command command = new ConcreteCommand(receiver);
// 创建请求者,把命令对象设置进去
Invoker invoker = new Invoker(command);
// 执行方法
invoker.action();
}
}
通过代码我们可以看到,命令模式把一条命令分为四步,先定义接收者,再创建执行命令对象,再创建请求者,最后执行命令方法。它的耦合度要比把所有的操作都封装到一个类中要低的多,而这也正是命令模式的精髓所在:把命令的调用者与执行者分开,使双方不必关心对方是如何操作的。
命令模式的优点:
命令模式的缺点:
命令模式的典型应用场景如下:
以生活中的看电视为例,其中遥控器就是命令发送者,电视就是请求接收者,分别对应:开机、关机、切换频道三个命令,实现代码如下。
interface Command {
void execute();
}
// 打开电视(命令)
class OpenTvCommand implements Command {
private TV tv;
public OpenTvCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.open();
}
}
// 更换电视频道(命令)
class ChangeTvCommand implements Command {
private TV tv;
public ChangeTvCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.change();
}
}
// 关闭电视(命令)
class CloseTvCommand implements Command {
private TV tv;
public CloseTvCommand(TV tv) {
this.tv = tv;
}
public void execute() {
tv.close();
}
}
// 电视机的具体动作
class TV {
public void open() {
System.out.println("打开电视机");
}
public void close() {
System.out.println("关闭电视机");
}
public void change() {
System.out.println("切换电视频道");
}
}
// 遥控器
class TvRemote {
private Command openTvCommand;
private Command closeTvCommand;
private Command changeTvCommand;
public TvRemote(Command openTvCommand, Command closeTvCommand, Command changeTvCommand) {
this.openTvCommand = openTvCommand;
this.closeTvCommand = closeTvCommand;
this.changeTvCommand = changeTvCommand;
}
// 打开电视
public void open() {
openTvCommand.execute();
}
// 关闭电视
public void close() {
closeTvCommand.execute();
}
// 换频道
public void change() {
changeTvCommand.execute();
}
}
class Client{
public static void main(String[] args) {
TV tv = new TV();
Command openTvCommand = new OpenTvCommand(tv);
Command closeTvCommand = new CloseTvCommand(tv);
Command changeTvCommand = new ChangeTvCommand(tv);
TvRemote control = new TvRemote(openTvCommand,closeTvCommand,changeTvCommand);
control.open();
control.change();
control.close();
}
}
命令模式是通过封装命令类来实现解耦调用者(发送命令)和接收者(执行命令),它的优点是可扩展性好,缺点是需要为不同的命令需要制定单独的命令类。你还知道哪些命令模式在生活中的例子呢?
若将上面代码改为使用循环的方式,又该如何修改呢?大家可以思考一下。