Command Patterns
GoF定义:将请求作为一个对象来处理。使得可以使用不同的请求、队列或者日志请求来参数化客户端。并且支持撤销操作。
概念
通常,四个概念是相互关联的
- command object:在接收端可以调用某个特定的方法,它保存着可以调用receiver方法的参数
- invoker:只知道命令接口(接收符合Command接口声明的对象),不知道具体哪个命令被调用
- client:持有invoker对象和command对象,客户端决定哪些命令在一个特定的时间点执行,要实现这个功能,客户端要将command对象传给invoker对象
- receiver:命令的具体操作定义在这里
例子
现实世界:我们不能改变过去发生的事情,但是我们希望原来可以那样做,可惜没有时光机的存在。但是日常生活中,我们可以不做或者重做很多事情,例如橡皮可以擦掉画的画,重新设计客厅。所以,取消和重做的操作是我们生活的一部分,我们通过一些内在或外在的命令来实现它们
代码世界:微软的Paint软件,我们通过工具栏可以随时undo/redo很多操作
展示

代码
public class CommandPatternEx
{
public static void main(String[] args)
{
System.out.println("***Command Pattern Demo***\n");
Receiver intendedreceiver=new Receiver();
/*Client holds Invoker and Command Objects*/
Invoker inv = new Invoker();
MyUndoCommand unCmd = new MyUndoCommand(intendedreceiver);
MyRedoCommand reCmd = new MyRedoCommand(intendedreceiver);
inv.executeCommand(unCmd);
inv.executeCommand(reCmd);
}
}
interface ICommand
{
void doSomething();
}
class MyUndoCommand implements ICommand
{
private Receiver receiver;
public MyUndoCommand(Receiver receiver)
{
this.receiver = receiver;
}
@Override
public void doSomething()
{
receiver.performUndoCommand();
}
}
class MyRedoCommand implements ICommand
{
private Receiver receiver;
public MyRedoCommand(Receiver receiver)
{
this.receiver = receiver;
}
@Override
public void doSomething()
{
receiver.performRedoCommand();
}
}
class Receiver
{
public void performUndoCommand()
{
System.out.println("Execution--Undo");
}
public void performRedoCommand()
{
System.out.println("Execution--Redo");
}
}
class Invoker
{
ICommand cmd;
public void executeCommand(ICommand cmd)
{
this.cmd = cmd;
this.cmd.doSomething();
}
}
Note
- 这个模式广泛应用于undo/redo操作
- 回调函数可以用这个模式设计(如果没有函数式接口,可以传入一个command对象,即在方法的不同状态下执行不同的命令)
- 当我们处理事务时很有用,可以响应数据的变化(结合2,当数据库数据在不同状态下执行不同命令)
- 命令易于扩展。它们和其它的对象没有什么不同,在使用Command对象时,不需要改变现在系统的类结构(扩展接口即可)
- 另一种模式叫做(chain of responsibility)这个模式中,我们将一个请求传给一系列的对象串(chain),希望这串对象中的任一个可以处理这个请求。但是在本例中,我们将请求传给了特定的对象(invoker对象)
思考
这个模式核心在于将命令和具体操作解耦,即(Command对象+Receiver对象),而Invoker对象作为统一的调命令接口防止了新建各种command对象调不同的方法。所有的command对象都是客户端组装完成(要调的命令所需的参数,且包含一个Receiver类),然后直接传入Invoker执行命令
浙公网安备 33010602011771号