前言
在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
概述
定义
命令模式(Command Pattern)将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销操作。
类图
- Command: 抽象命令类
- ConcreteCommand: 具体命令类
- Invoker: 调用者
- Receiver: 接收者
- Client: 客户端
注意
- 命令模式将发出请求的对象和执行请求的对象解耦
- 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作
- 调用者通过调用命令对象的excute()发出请求,这会使得接收者的动作被调用
宏命令是命令的一种简单的延伸,允许调用多个命令
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,发送者只需要知道如何发送命令即可,不需要知道命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。
设计模式的实现
场景说明
模拟遥控器控制电视场景。电视剧是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。
代码实现
package command;
/**
* <p>ClassName Command
* <p>Description Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:17
*/
public interface Command {
void execute();
}
package command;
/**
* <p>ClassName Television
* <p>Description 电视机类
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:18
*/
public class Television {
public void open() {
System.out.println( "打开电视机......" );
}
public void close() {
System.out.println( "关闭电视机......" );
}
public void changeChannel() {
System.out.println( "切换电视频道......" );
}
}
package command;
/**
* <p>ClassName Controller
* <p>Description 遥控器类
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:22
*/
public class Controller {
private Command openTVCommand; // 开电视命令类
private Command closeTVCommand; // 关电视命令类
private Command changeChannelCommand; // 换频道命令类
public Controller(Command openTvCommand, Command closeTvCommand, Command changeChannelCommand) {
this.openTVCommand = openTvCommand;
this.closeTVCommand = closeTvCommand;
this.changeChannelCommand = changeChannelCommand;
}
/**
* 打开电视剧
*/
public void open() {
openTVCommand.execute();
}
/**
* 关闭电视机
*/
public void close() {
closeTVCommand.execute();
}
/**
* 换频道
*/
public void change() {
changeChannelCommand.execute();
}
}
package command;
/**
* <p>ClassName OpenTvCommand
* <p>Description 遥控器的三个按钮:开电视具体命令类
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:24
*/
public class OpenTvCommand implements Command {
private Television tv;
public OpenTvCommand() {
tv = new Television();
}
public void execute() {
tv.open();
}
}
package command;
/**
* <p>ClassName ChangeChannelCommand
* <p>Description 遥控器的三个按钮:换频道具体命令类
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:26
*/
public class ChangeChannelCommand implements Command {
private Television tv;
public ChangeChannelCommand() {
tv = new Television();
}
public void execute() {
tv.changeChannel();
}
}
package command;
/**
* <p>ClassName CloseTvCommand
* <p>Description 遥控器三个按钮:关电视具体命令类
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:26
*/
public class CloseTvCommand implements Command {
private Television tv;
public CloseTvCommand() {
tv = new Television();
}
public void execute() {
tv.close();
}
}
package command;
/**
* <p>ClassName Client
* <p>Description 客户端
* <p>Author ChongLou
* <p>Version
* <p>Date 2017/8/13 23:32
*/
public class Client {
public static void main(String a[]) {
Command openCommand, closeCommand, changeCommand;
openCommand = new OpenTvCommand();
closeCommand = new CloseTvCommand();
changeCommand = new ChangeChannelCommand();
// 向控制器注册命令
Controller control = new Controller( openCommand, closeCommand, changeCommand );
control.open(); //打开电视机
control.change(); //换频道
control.close(); //关闭电视机
}
}
运行结果
总结
关于前言中所说的撤销操作,这里就不在进行累述了。主要的思路就是在Invoker中记录之前的一个或者多个状态。在必要时恢复。
命令模式的更多用途:队列请求(这里是有些模糊?)、日志请求。