定义:
将来自客户端的请求传入一个对象,从而使你可用不同的请求对客户进行参数化。用于“行为请求者”与“行为实现者”解耦,可实现二者之间的松耦合,以便适应变化。分离变化与不变的因素。
命令模式将“请求”封装成对象,以便使用不同的请求、队列或日志来参数化其它对象。命令模式也支持可撤销操作。
UML图:

Client:客户。
Invoker:调用者,可类比遥控电视机代码中的遥控器。
Command:命令,用于解耦目标对象与调用者之间的抽象命令对象。一般为接口或抽象类,有一个execute()方法。
ConcreteCommand:具体的命令,继承Command,封装了具体的一个操作。
ConcreteCommand:具体的命令,继承Command,封装了具体的一个操作。
Receiver:接收者,接收调用者请求执行操作的目标对象。可以类比遥控电视机代码中的电视机。
实现:
public interface Command {
public void execute();
}
public class ConcreteCommand implements Command {
private Receiver receiver = null;
private String state;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
public class Receiver {
public void action(){
//真正执行命令操作的功能代码
}
}
public class Invoker {
private Command command = null;
public void setCommand(Command command) {
this.command = command;
}
public void runCommand() {
command.execute();
}
}
public class Client {
public void assemble(){
//创建接收者
Receiver receiver = new Receiver();
//创建命令对象,设定它的接收者
Command command = new ConcreteCommand(receiver);
//创建Invoker,把命令对象设置进去
Invoker invoker = new Invoker();
invoker.setCommand(command);
}
public void execute();
}
public class ConcreteCommand implements Command {
private Receiver receiver = null;
private String state;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
public class Receiver {
public void action(){
//真正执行命令操作的功能代码
}
}
public class Invoker {
private Command command = null;
public void setCommand(Command command) {
this.command = command;
}
public void runCommand() {
command.execute();
}
}
public class Client {
public void assemble(){
//创建接收者
Receiver receiver = new Receiver();
//创建命令对象,设定它的接收者
Command command = new ConcreteCommand(receiver);
//创建Invoker,把命令对象设置进去
Invoker invoker = new Invoker();
invoker.setCommand(command);
}
以电视机的遥控器为例子:
//命令接收者
public class Tv {
public int currentChannel = 0;
public void turnOn() {
System.out.println("The televisino is on.");
}
public void turnOff() {
System.out.println("The television is off.");
}
public void changeChannel(int channel) {
this.currentChannel = channel;
System.out.println("Now TV channel is " + channel);
}
}
//执行命令的接口
public interface Command {
void execute();
}
//开机命令
public class CommandOn implements Command {
private Tv myTv;
public CommandOn(Tv tv) {
myTv = tv;
}
public void execute() {
myTv.turnOn();
}
}
//关机命令
public class CommandOff implements Command {
private Tv myTv;
public CommandOff(Tv tv) {
myTv = tv;
}
public void execute() {
myTv.turnOff();
}
}
//频道切换命令
public class CommandChange implements Command {
private Tv myTv;
private int channel;
public CommandChange(Tv tv, int channel) {
myTv = tv;
this.channel = channel;
}
public void execute() {
myTv.changeChannel(channel);
}
}
//可以看作是遥控器吧
public class Control {
private Command onCommand, offCommand, changeChannel;
public Control(Command on, Command off, Command channel) {
onCommand = on;
offCommand = off;
changeChannel = channel;
}
public void turnOn() {
onCommand.execute();
}
public void turnOff() {
offCommand.execute();
}
public void changeChannel() {
changeChannel.execute();
}
}
//测试类
public class Client {
public static void main(String[] args) {
// 命令接收者
Tv myTv = new Tv();
// 开机命令
CommandOn on = new CommandOn(myTv);
// 关机命令
CommandOff off = new CommandOff(myTv);
// 频道切换命令
CommandChange channel = new CommandChange(myTv, 2);
// 命令控制对象
Control control = new Control(on, off, channel);
// 开机
control.turnOn();
// 切换频道
control.changeChannel();
// 关机
control.turnOff();
}
}
public class Tv {
public int currentChannel = 0;
public void turnOn() {
System.out.println("The televisino is on.");
}
public void turnOff() {
System.out.println("The television is off.");
}
public void changeChannel(int channel) {
this.currentChannel = channel;
System.out.println("Now TV channel is " + channel);
}
}
//执行命令的接口
public interface Command {
void execute();
}
//开机命令
public class CommandOn implements Command {
private Tv myTv;
public CommandOn(Tv tv) {
myTv = tv;
}
public void execute() {
myTv.turnOn();
}
}
//关机命令
public class CommandOff implements Command {
private Tv myTv;
public CommandOff(Tv tv) {
myTv = tv;
}
public void execute() {
myTv.turnOff();
}
}
//频道切换命令
public class CommandChange implements Command {
private Tv myTv;
private int channel;
public CommandChange(Tv tv, int channel) {
myTv = tv;
this.channel = channel;
}
public void execute() {
myTv.changeChannel(channel);
}
}
//可以看作是遥控器吧
public class Control {
private Command onCommand, offCommand, changeChannel;
public Control(Command on, Command off, Command channel) {
onCommand = on;
offCommand = off;
changeChannel = channel;
}
public void turnOn() {
onCommand.execute();
}
public void turnOff() {
offCommand.execute();
}
public void changeChannel() {
changeChannel.execute();
}
}
//测试类
public class Client {
public static void main(String[] args) {
// 命令接收者
Tv myTv = new Tv();
// 开机命令
CommandOn on = new CommandOn(myTv);
// 关机命令
CommandOff off = new CommandOff(myTv);
// 频道切换命令
CommandChange channel = new CommandChange(myTv, 2);
// 命令控制对象
Control control = new Control(on, off, channel);
// 开机
control.turnOn();
// 切换频道
control.changeChannel();
// 关机
control.turnOff();
}
}
命令模式的更多用途:
队列请求:如日程安排、线程池、工作队列等。
工作队列:在某一段添加命令,然后另一端则是线程。线程从队列中取出一个命令,调用execute()方法,等待这个调用完成,然后将此命令对象丢弃,再取出下一个命令....
工作队列类和进行计算的对象之间完全是解耦的。此刻线程可能进行财务运算,下一刻却在读取网络数据。工作队列不在乎到底做些什么,它们只知道实现命令模式的对象,就可以放入队列里,当线程可用时,就调用此对象的execute()方法。
日志请求:
某些应用需要我们将所有动作都记录在日志中,并能在系统死机之后,重新调用这些动作恢复到之前状态。通过新增两个方法(store()、load()),命令模式能够支持只一点。在Java中可以利用对象的序列化(Serialization)实现这些方法,但是一般认为序列化最好还是只用在对象的持久化上(persistence)。
利用命令模式,将历史记录存储在磁盘中。一旦系统死机,我们就可以讲命令对象重新加载,并成批的调用这些对象的execute()方法。
许多调用大型数据结构的动作应用无法在每次改变发生时被快速存储。通过记录日志,我们可以将上次检查点之后的所有操作记录记录下来,如果系统出状况,从检查点开始应用这些操作。