Command

命令

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
可将“动作的请求者”从“动作的执行者”对象中解耦。

适用性

  • 抽象出待执行的动作以参数化某对象。Command是回调机制的一个面向对象的替代品。
  • 在不同的时刻指定、排列和执行请求。Command对象有与初始请求无关的生存期。
  • 支持取消操作。Command有一个Execute接口和一个Unexecute接口。Command被存储在一个历史列表中。
  • 支持修改日志,这样当系统崩溃时,这些修改可以重做一遍。在Command接口中添加装载和存储操作,可以用来保持变动的一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下来的命令并用Execute操作重新执行它们。

典型情境

一个遥控器同时控制电视、电灯等等。
Command Brief
Command Scenario

结构

Command Class 1
Command Class 2

Command - 声明执行操作的接口。
ConcreteCommand - 将一个接收者对象绑定与一个动作。调用接收者相应的操作,以实现Execute。
Client - 创建一个具体命令对象并设定它的接收者。
Invoker - 要求该命令执行这个请求。
Receiver - 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

协作:
Client创建一个ConcreteCommand对象并指定它的Receiver对象。
某Invoker对象存储该ConcreteCommand对象。
该Invoker通过调用Command对象的Execute操作来提交一个请求。若该命令是可撤销的,ConcreteCommand就在执行Execute操作之前存储当前状态以用于取消该命令。
ConcreteCommand对象对调用它的Receiver的一些操作以执行该请求。

Command Sequence

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <iostream>
#include <list>
//---------------------------------------------------
class Receiver
{
public:
void action(bool state)
{

if (state)
{
std::cout<<"Go!Go!Go!"<<std::endl;
}else
{
std::cout<<"Back!Back!Back!"<<std::endl;
}

}
};
//---------------------------------------------------
class Command
{
public:
virtual void execute(){}
virtual void undo(){}
};
//---------------------------------------------------
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver* recv) : Command(), m_receiver(recv), m_state(true){}
virtual void execute()
{

m_state = true;
if (!m_receiver) return;
m_receiver->action(m_state);
}
virtual void undo()
{

m_state = false;
if (!m_receiver) return;
m_receiver->action(m_state);
}
protected:
Receiver* m_receiver;
bool m_state;
};
//---------------------------------------------------
class MultiCommand : public Command
{
public:
virtual void add(Command* com)
{

m_cmds.push_back(com);
}
virtual void remove(Command* com)
{

m_cmds.remove(com);
}
virtual void execute()
{

std::cout<<"Multi: "<<std::endl;
for (std::list<Command*>::iterator it = m_cmds.begin(); it != m_cmds.end(); ++it)
{
if (*it)
{
(*it)->execute();
}
}
}
virtual void undo()
{

std::cout<<"Multi: "<<std::endl;
for (std::list<Command*>::reverse_iterator it = m_cmds.rbegin(); it != m_cmds.rend(); ++it)
{
if (*it)
{
(*it)->undo();
}
}
}
protected:
std::list<Command*> m_cmds;
};
//---------------------------------------------------
class Invoker
{
public:
virtual void execute_command()
{

std::cout<<"[Execute]"<<std::endl;
Command* com = m_executecmds.front();
m_executecmds.pop_front();
if (!com) return;
com->execute();
m_undocmds.push_back(com);
}
virtual void undo_command()
{

std::cout<<"[Undo]"<<std::endl;
Command* com = m_undocmds.back();
m_undocmds.pop_back();
if (!com) return;
com->undo();
m_executecmds.push_back(com);
}
virtual void store_command(Command* command)
{

m_executecmds.push_back(command);
}
protected:
std::list<Command*> m_executecmds;
std::list<Command*> m_undocmds;
};
//---------------------------------------------------
class Client
{
public:
void set_all(Invoker* ivk)
{

if (!ivk) return;
Receiver* r1 = new Receiver();
ConcreteCommand* c1 = new ConcreteCommand(r1);
ivk->store_command(c1);

ConcreteCommand* c2 = new ConcreteCommand(r1);
ConcreteCommand* c3 = new ConcreteCommand(r1);
ConcreteCommand* c4 = new ConcreteCommand(r1);
MultiCommand* cm = new MultiCommand();
cm->add(c2);
cm->add(c3);
cm->add(c4);
ivk->store_command(cm);
}
};
//---------------------------------------------------
int main()
{

Invoker ivk;
Client clt;
clt.set_all(&ivk);
ivk.execute_command();
ivk.execute_command();
ivk.undo_command();
ivk.undo_command();
system("Pause");
}

相关模式

  • Composite模式可被用来实现宏命令。
  • Memento模式可用来保存某个状态,命令用这一状态来取消它的效果。在被放入历史列表前必须被拷贝的命令起到一种原型的作用。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First 设计模式