命令模式(行为型)

前言


一般的文档编辑器都会提供一个主菜单(Menu),主菜单中包含一些菜单项(MenuItem),每个菜单项包含很多的命令操作,包括打开命令,创建命令,编辑命令等等,要设计这样的文档编辑系统,可以考虑使用命令模式。

命令模式


意图

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作,别名为动作(Action)模式或事务(Transaction)模式

命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开
命令模式是回调机制的一个面向对象替代品,所谓回调函数是指函数现在某处注册,而它将在稍后某个需要的时候被调用

参与者

  • Command
    抽象命令类,在其中执行请求的execute()方法,通过这些方法可以调用请求接收者的相关操作

  • ConcreteCommand
    具体命令类,抽象命令类的子类,处理用户请求,实现抽象命令类的方法
    一般持有接收者对象的引用。它对应具体的接收者对象,将接收者对象的动作绑定其中,在实现execute()方法时,将调用接收者对象的相关操作(Action)

  • Invoker
    调用者即请求发送者,持有抽象命令对象的引用.它通过命令对象来执行请求。
    一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系
    在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作

  • Receiver
    接收者,接收者执行与请求相关的操作,它具体实现对请求的业务处理

  • Client
    创建一个ConcreteCommand命令对象,并指定它的Receiver对象

模式结构

command

代码实现

1.首先定义接收者Receiver,并提供Action()接口:

1
2
3
4
5
6
7
8
9
// Receiver 接收者 :具体命令内容的实现
class Receiver
{
public:
void Action()
{
cout << "Receiver: Action!" << endl;
}
};

2.再定义抽象命令类Command,并提供公共接口Execute():

1
2
3
4
5
6
// Command 抽象命令 :定义公共接口
class Command
{
public:
virtual void Execute() = 0;
};

3.再定义Command类的一个具体命令子类,并实现其中的Execute()接口,持有命令接收者的对象,该接口主要作用是调用不同接收者ReceiverAction()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
// ConcreteCommand 具体命令:封装的一层
class ConcreteCommand : public Command
{
private:
Receiver *m_pReceiver;
public:
ConcreteCommand(Receiver *prec) : m_pReceiver(prec) {};
public:
void Execute()
{
m_pReceiver->Action();
}
};

4.定义一个命令调用者,持有抽象命令对象,并提供一个Invoke()接口,供客户端调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Invoker 命令调用者 :调用命令
class Invoker
{
private:
Command *m_pCommand;
public:
Invoker(Command *pcmd): m_pCommand(pcmd) {};
// 通过构造注入具体命令,也可以通过提供set方法来注入不同的具体命令对象
public:
void Invoke()
{
m_pCommand->Execute();
}
};

5.测试命令模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void CommandTest_General()
{
// 命令实现
Receiver *pR = new Receiver();
// 命令 中间层
Command *pC = new ConcreteCommand(pR);
// 命令调用
Invoker *pI = new Invoker(pC);

pI->Invoke();

SAFE_RELASE_POINTER(pR);
SAFE_RELASE_POINTER(pC);
SAFE_RELASE_POINTER(pI);
}

4.运行结果:

Receiver: Action!

命令模式的分类

命令模式根据应用的使用场景,可以分为以下几类:

一般场景命令模式

即一般场景下的请求发送者和请求接收处理者解耦,一般一个请求对应于一个请求处理

命令队列

将多个请求排队,当一个请求发送者发送一个请求时,将不止一个请求接收者产生响应,这些请求接收者将逐个执行业务方法,完成对请求的处理
一般实现方法是增加一个CommandQueue类,由该类来负责存储多个命令对象,而不同的命令对象可以对应不同的请求接收者,代码实现如下:

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
// 命令队列
class CommandQueue
{
private:
list<Command*> _listCommand;
public:
void addCommand(Command &cmd)
{
_listCommand.push_back(&cmd);
}
void removeCommand(Command &cmd)
{
_listCommand.remove(&cmd);
}
void Execute()
{
for (list<Command*>::iterator it = _listCommand.begin();
it!= _listCommand.end(); ++it)
{
(*it)->Execute(); // 遍历命令集合中每个命令,并执行
}
}
};

// 命令队列调用者
class CommandQueueInvoker
{
private:
CommandQueue *_commandQueue;
public:
CommandQueueInvoker(CommandQueue &cmdQueue) :_commandQueue(&cmdQueue) {};
void setCommandQueue(CommandQueue &cmdQueue)
{
_commandQueue = &cmdQueue;
}
void Invoke()
{
_commandQueue->Execute();
}
};

命令队列与“批处理”有点类似。批处理—可以对一组对象(命令)进行批量处理,当一个发送者发送请求后,将有一系列接收者对请求作出响应

带有撤销操作的命令模式

在命令模式中,我们可以通过调用一个命令对象的execute()方法来实现对请求的处理,如果需要撤销(Undo)请求,可通过在命令类中增加一个逆向操作来实现,

实现计算机加减乘除操作,并带有撤销操作

1.首先定义命令接受者,即各种操作业务的具体实现者:

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
// 命令接受者,具体的业务实现者 Adder
class Adder
{
public:
float add(float leftOperand, float rightoperand)
{
cout << leftOperand << " add " << rightoperand << endl;
return (leftOperand + rightoperand);
}
};

// 命令接受者,具体的业务实现者 Minuser
class Minuser
{
public:
float minus(float leftOperand, float rightoperand)
{
cout << leftOperand << " minus " << rightoperand << endl;
return (leftOperand - rightoperand);
}
};

// 命令接受者,具体的业务实现者 Multiplater
class Multiplater
{
public:
float multiplate(float leftOperand, float rightoperand)
{
cout << leftOperand << " multiplate " << rightoperand << endl;
return (leftOperand * rightoperand);
}
};

// 命令接受者,具体的业务实现者 Diviser
class Diviser
{
public:
float dive(float leftOperand, float rightoperand)
{
assert(0 != rightoperand);
cout << leftOperand << " dive " << rightoperand << endl;
return (leftOperand / rightoperand);
}
};

2.定义抽象命令对象,和具体的命令对象,分别提供和实现compute()unCompute()两种方法:

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
// 抽象计算命令ComputerCommand
class ComputerCommand
{
public:
virtual float compute(float leftOperand, float rightOperand) = 0;
virtual float unCompute(float leftOperand, float rightOperand) = 0;
};

// 具体add计算命令
class AddCommand : public ComputerCommand
{
private:
Adder *_adder;
float _result;
public:
AddCommand(Adder *adder) : _adder(adder), _result(0) {};
public:
virtual float compute(float leftOperand, float rightOperand)
{
_result = _adder->add(leftOperand, rightOperand);
return _result;
}
virtual float unCompute(float leftOperand, float rightOperand)
{
_result = _adder->add(leftOperand, -rightOperand);
return _result;
}
};

// 具体minus计算命令
class MinusCommand : public ComputerCommand
{
private:
Minuser *_minuser;
float _result;
public:
MinusCommand(Minuser *minuser) : _minuser(minuser), _result(0) {};
public:
virtual float compute(float leftOperand, float rightOperand)
{
_result = _minuser->minus(leftOperand, rightOperand);
return _result;
}
virtual float unCompute(float leftOperand, float rightOperand)
{
_result = _minuser->minus(leftOperand, -rightOperand);
return _result;
}
};

// 具体multiplate计算命令
class MultiplateCommand : public ComputerCommand
{
private:
Multiplater *_multiplater;
float _result;
public:
MultiplateCommand(Multiplater *multiplater) : _multiplater(multiplater) , _result(0) {};
public:
virtual float compute(float leftOperand, float rightOperand)
{
_result = _multiplater->multiplate(leftOperand, rightOperand);
return _result;
}
virtual float unCompute(float leftOperand, float rightOperand)
{
_result = _multiplater->multiplate(leftOperand, 1/rightOperand);
return _result;
}
};

// 具体dive计算命令
class DiveCommand : public ComputerCommand
{
private:
Diviser *_diviser;
float _result;
public:
DiveCommand(Diviser *diviser) : _diviser(diviser), _result(0) {};
public:
virtual float compute(float leftOperand, float rightOperand)
{
_result = _diviser->dive(leftOperand, rightOperand);
return _result;
}
virtual float unCompute(float leftOperand, float rightOperand)
{
_result = _diviser->dive(leftOperand, 1/rightOperand);
return _result;
}
};

3.命令的调用者,持有两个stack,分别为撤销操作命令和恢复撤销操作命令:

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
class ComputerInvoker
{
private:
ComputerCommand *_currentComputerCommand; // 当前操作
stack<ComputerCommand*> _stackUndoCommand; // 撤销操作堆栈(FILO)
stack<ComputerCommand*> _stackRedoCommand; // 恢复撤销操作堆栈(FILO)
float _computeResult; // 计算结果
public:
ComputerInvoker(ComputerCommand *cmd) : _currentComputerCommand(cmd), _computeResult(0) {};
public:
void setComputerCommand(ComputerCommand *cmd)
{
_currentComputerCommand = cmd;
}
void invokeCompute(float operand) // 正常顺序操作
{
_computeResult = _currentComputerCommand->compute(_computeResult, operand); //执行 正常操作
_stackUndoCommand.push(_currentComputerCommand); // 压入正常操作命令到 撤销操作的stack
cout << "normal compute: result is : " << _computeResult << endl;
}
void invokeUncompute(float operand) // 撤销操作
{
if (_stackUndoCommand.empty())
{
cout << "undo command stack is empty!" << endl;
return;
}
_currentComputerCommand = _stackUndoCommand.top(); // 先取 撤销操作的stack顶元素
_stackUndoCommand.pop(); // 弹出 撤销操作的stack顶元素
_computeResult = _currentComputerCommand->unCompute(_computeResult, operand); //执行 撤销操作
_stackRedoCommand.push(_currentComputerCommand); // 压入撤销操作命令到 恢复操作的stack
cout << "undo compute: result is : " << _computeResult << endl;
}
void invokeRecompute(float operand) // 恢复撤销操作
{
if (_stackRedoCommand.empty())
{
cout << "resume do command stack is empty!" << endl;
return;
}
_currentComputerCommand = _stackRedoCommand.top(); // 先取 恢复撤销操作的stack顶元素
_stackRedoCommand.pop(); // 弹出 恢复撤销操作的stack顶元素
_computeResult = _currentComputerCommand->compute(_computeResult, operand); //执行 恢复撤销操作
_stackUndoCommand.push(_currentComputerCommand); // 压入恢复撤销操作命令到 撤销操作的stack
cout << "redo compute: result is : " << _computeResult << endl;
}
float getComputeResult()
{
return _computeResult;
}
};

4.测试带有撤销操作的命令模式:

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
void CommandTest_Compute()
{
Adder *adder = new Adder();
ComputerCommand *addCmd = new AddCommand(adder);
Minuser *minuser = new Minuser();
ComputerCommand *minusCmd = new MinusCommand(minuser);
Multiplater *multiplater = new Multiplater();
ComputerCommand *multiplateCmd = new MultiplateCommand(multiplater);
Diviser *diviser = new Diviser();
ComputerCommand *diveCmd = new DiveCommand(diviser);

ComputerInvoker *computeInvoke = new ComputerInvoker(addCmd); // 初始化为add 且 + 50
computeInvoke->invokeCompute(50); // 0 + 50
computeInvoke->setComputerCommand(minusCmd); // -20
computeInvoke->invokeCompute(20);
computeInvoke->setComputerCommand(multiplateCmd); // *3
computeInvoke->invokeCompute(3);
computeInvoke->setComputerCommand(diveCmd); // /9
computeInvoke->invokeCompute(9);
computeInvoke->setComputerCommand(addCmd); // + 10
computeInvoke->invokeCompute(10);
cout << "*** last normal compute result is : " << computeInvoke->getComputeResult() << " ***" << endl;

computeInvoke->invokeUncompute(10); // 撤销 +10
computeInvoke->invokeUncompute(9);// 撤销 /9
computeInvoke->invokeUncompute(3); // 撤销 *3
computeInvoke->invokeUncompute(20); // 撤销 -20
computeInvoke->invokeUncompute(50); // 撤销 +50
cout << "*** last undo compute result is : " << computeInvoke->getComputeResult() << " ***" << endl;

computeInvoke->invokeRecompute(50); // 恢复撤销 +50
computeInvoke->invokeRecompute(20); // 恢复撤销 -20
computeInvoke->invokeRecompute(3); // 恢复撤销 *3
computeInvoke->invokeRecompute(9); // 恢复撤销 /9
computeInvoke->invokeRecompute(10); // 恢复撤销 +10
cout << "*** last redo compute result is : " << computeInvoke->getComputeResult() << " ***" << endl;

// 输出结果
float finalResult = computeInvoke->getComputeResult();
cout << "*** final compute result is " << finalResult << " ***" << endl;

SAFE_RELASE_POINTER(adder);
SAFE_RELASE_POINTER(minuser);
SAFE_RELASE_POINTER(multiplater);
SAFE_RELASE_POINTER(diviser);

SAFE_RELASE_POINTER(addCmd);
SAFE_RELASE_POINTER(minusCmd);
SAFE_RELASE_POINTER(multiplateCmd);
SAFE_RELASE_POINTER(diveCmd);

SAFE_RELASE_POINTER(computeInvoke);
}

5.运行结果:

0 add 50
normal compute: result is : 50
50 minus 20
normal compute: result is : 30
30 multiplate 3
normal compute: result is : 90
90 dive 9
normal compute: result is : 10
10 add 10
normal compute: result is : 20
\*\*\* last normal compute result is : 20 \*\*\*
20 add -10
undo compute: result is : 10
10 dive 0.111111
undo compute: result is : 90
90 multiplate 0.333333
undo compute: result is : 30
30 minus -20
undo compute: result is : 50
50 add -50
undo compute: result is : 0
\*\*\* last undo compute result is : 0 \*\*\*
0 add 50
redo compute: result is : 50
50 minus 20
redo compute: result is : 30
30 multiplate 3
redo compute: result is : 90
90 dive 9
redo compute: result is : 10
10 add 10
redo compute: result is : 20
\*\*\* last redo compute result is : 20 \*\*\*
\*\*\* final compute result is 20 \*\*\*

请求日志的命令模式

请求日志就是将请求的历史记录保存下来,通常以日志文件(Log File)的形式永久存储在计算机中

1.可以为系统提供一种恢复机制,在请求日志文件中可以记录用户对系统的每一步操作,从而让系统能够顺利恢复到某一个特定的状态
2.用于实现批处理,在一个请求日志文件中可以存储一系列命令对象,如一个命令队列

在上面带恢复功能的简易计算器基础上增加请求日志功能

1.增加操作命令日志的list:

1
2
3
4
5
6
7
8
9
10
typedef struct tag_computeLog
{
//typedef float(*pComputeFunc)(float, float);
//pComputeFunc compute;
ComputerCommand* cmd;
float leftOperand;
float rightOperand;
}computeLog;

list<computeLog> _listComputeLogCommand; // 执行操作记录的list

2.修改调用执行计算的方法,在其中添加command到list:

1
2
3
4
5
6
7
8
9
10
11
void invokeCompute(float operand) // 正常顺序操作
{
computeLog log;
log.cmd = _currentComputerCommand;
log.leftOperand = _computeResult;
log.rightOperand = operand;
_listComputeLogCommand.push_back(log); // 添加操作command记录到list

_computeResult = _currentComputerCommand->compute(_computeResult, operand); //执行 正常操作
...
}

3.增加新的日志命令操作,循环调用操作command记录list中的命令:

1
2
3
4
5
6
7
8
9
void invokeLogCommand(void)
{
_computeResult = 0;
for (list<computeLog>::iterator it = _listComputeLogCommand.begin();
it != _listComputeLogCommand.end(); ++it)
{
_computeResult =((*it).cmd->compute((*it).leftOperand, (*it).rightOperand));
}
}

宏命令

宏命令(Macro Command)又称为组合命令,它是组合模式和命令模式联用的产物。宏命令是一个具体命令类,它拥有一个集合属性,在该集合中包含了对其他命令对象的引用。通常宏命令不直接与请求接收者交互,而是通过它的集合成员来调用接收者的方法

宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法
执行一个宏命令将触发多个具体命令的执行,从而实现对命令的批处理

在上面带恢复和日志功能的简易计算器基础上增加宏命令(批处理,依次调用各个命令)

1.修改抽象命令类ComputerCommand,增加增加和删除命令集合元素的操作:

1
2
3
4
5
6
7
8
9
10
11
12
// 抽象计算命令ComputerCommand
class ComputerCommand
{
public:
virtual float compute(float leftOperand, float rightOperand) = 0;
virtual float unCompute(float leftOperand, float rightOperand) = 0;
// for Macro Command:
public:
virtual void insertCommand(ComputerCommand *cmd) {};
virtual void removeCommand(ComputerCommand *cmd) {};
ComputerCommand* getCommand(int i) { return NULL; }
};

2.增加宏命令具体类MacroCommand,继承于抽象命令类ComputerCommand,并实现其各个方法:

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
// 批计算处理:计算给定的两个操作数的四种操作(+ - * /)结果的和
class MacroCommand : public ComputerCommand
{
private:
vector<ComputerCommand*> _vecCmd;
public:
MacroCommand() {};
public:
void insertCommand(ComputerCommand *cmd)
{
_vecCmd.push_back(cmd);
}
void removeCommand(ComputerCommand *cmd)
{
for (vector<ComputerCommand*>::iterator it = _vecCmd.begin();
it != _vecCmd.end(); ++it)
{
if (*it == cmd)
{
_vecCmd.erase(it);
}
}
}
ComputerCommand* getCommand(int i)
{
assert(i < _vecCmd.size());
return _vecCmd[i];
};

// 依次执行集合中的命令
float compute(float leftOperand, float rightOperand)
{
float result = 0;
for (vector<ComputerCommand*>::iterator it = _vecCmd.begin();
it != _vecCmd.end(); ++it)
{
result += (*it)->compute(leftOperand, rightOperand);
}
return result;
}

float unCompute(float leftOperand, float rightOperand)
{
float result = 0;
for (vector<ComputerCommand*>::iterator it = _vecCmd.begin();
it != _vecCmd.end(); ++it)
{
result += (*it)->unCompute(leftOperand, rightOperand);
}
return result;
}
};

3.使用宏命令,与使用简单命令类似,只是使用前,先添加命令元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Adder *adder = new Adder();
ComputerCommand *addCmd = new AddCommand(adder);
Minuser *minuser = new Minuser();
ComputerCommand *minusCmd = new MinusCommand(minuser);
Multiplater *multiplater = new Multiplater();
ComputerCommand *multiplateCmd = new MultiplateCommand(multiplater);
Diviser *diviser = new Diviser();
ComputerCommand *diveCmd = new DiveCommand(diviser);

// add simple command to Macro Command;
ComputerCommand *macroCmd = new MacroCommand();
macroCmd->insertCommand(addCmd);
macroCmd->insertCommand(minusCmd);
macroCmd->insertCommand(multiplateCmd);
macroCmd->insertCommand(diveCmd);

// invoke Macro Command just like Simple Command;
computeInvoke->setComputerCommand(macroCmd); // 批计算处理
computeInvoke->invokeCompute(2);

使用场景

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者可以有不同的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象本身仍然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可以通过请求日志文件等机制来具体实现
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作
  • 系统需要将一组操作组合在一起形成宏命令

优缺点

  • 优点
    • 降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦
    • 新的命令可以很容易地加入到系统中
  • 缺点
    • 使用命令模式可能会导致某些系统有过多的具体命令类

命令模式具体实例


编辑器操作问题

使用命令模式简单实现前言所述的文档编辑器简单操作功能

  • 支持撤销
  • 支持宏命令
  • 支持操作日志恢复

代码实现
1.定义抽象的命令类DocCommand:

1
2
3
4
5
6
7
8
9
10
11
12
13
// command
class DocCommand
{
public:
DocCommand() {};
virtual ~DocCommand() {};
public:
virtual void execute(void) = 0;
virtual void unexecute(void) = 0;
virtual void addDocCommand(DocCommand* doc) {};
virtual void removeDocCommand(DocCommand* doc) {};
virtual Document* getCurrentOpenDoc(void) { return NULL; }
};

2.分别定义命令类DocCommand的子类OpenDocCommandEditDocCommandSaveDocCommandCloseDocCommand及宏命令MacroDocCommand:

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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// open 
class OpenDocCommand : public DocCommand
{
public:
OpenDocCommand(Application *app) : _app(app), _currentOpenDoc(NULL), _response("") {};
public:
void execute(void)
{
askUser();
if (!_response.empty())
{
_currentOpenDoc = _app->getDocByName(_response);
if (NULL != _currentOpenDoc)
{
_currentOpenDoc->open();
}
}
}
void unexecute(void)
{
cout << "can not unexecute open operate!!!" << endl;
}

private:
void askUser()
{
char confirm;
cout << "please input a name for the doc: " << endl;
cin >> _response;
cout << "you have enter a doc named: " << _response << endl;
cout << "confirm? (Y/N)" << endl;
cin >> confirm;
switch (confirm)
{
case 'y':
case 'Y':
break;
case 'N':
case 'n':
default:
_response = "";
break;
}
};
public:
Document* getCurrentOpenDoc(void)
{
return _currentOpenDoc;
}
private:
Application *_app;
Document *_currentOpenDoc;
string _response;
};

//edit
class EditDocCommand : public DocCommand
{
public:
EditDocCommand(Document* doc) : _doc(doc) {};
public:
void execute(void)
{
if (NULL != _doc)
{
_doc->edit();
}
}
void unexecute(void)
{
if (NULL != _doc)
{
_doc->unedit();
}
}
Document* getCurrentOpenDoc(void)
{
return _doc;
}
private:
Document *_doc;
};

//save
class SaveDocCommand : public DocCommand
{
public:
SaveDocCommand(Document* doc) : _doc(doc) {};
public:
void execute(void)
{
if (NULL != _doc)
{
_doc->save();
}
}
void unexecute(void)
{
if (NULL != _doc)
{
_doc->unsave();
}
}
Document* getCurrentOpenDoc(void)
{
return _doc;
}
private:
Document *_doc;
};

// close
class CloseDocCommand : public DocCommand
{
public:
CloseDocCommand(Document* doc) : _doc(doc) {};
public:
void execute(void)
{
if (NULL != _doc)
{
_doc->close();
}
}
void unexecute(void)
{
cout << "can not unexecute close operate!!!" << endl;
}
Document* getCurrentOpenDoc(void)
{
return _doc;
}
private:
Document *_doc;
};

// macro
class MacroDocCommand : public DocCommand
{
public:
MacroDocCommand() {};
public:
void execute(void)
{
for (list<DocCommand*>::iterator it = _listDoc.begin();
it != _listDoc.end(); ++it)
{
(*it)->execute();
}
}
void unexecute(void)
{
for (list<DocCommand*>::iterator it = _listDoc.begin();
it != _listDoc.end(); ++it)
{
(*it)->unexecute();
}
}
public:
void addDocCommand(DocCommand* doc)
{
_listDoc.push_back(doc);
}
void removeDocCommand(DocCommand* doc)
{
_listDoc.remove(doc);
}
private:
list<DocCommand*> _listDoc;
};

3.定义命令的接收者即,实际业务的实现者DocumentApplication:

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
// receiver
class Document
{
private:
string _name;
public:
Document(string name) :_name(name) {};
public:
void open(void)
{
cout << "open document " << _name << endl;
}
void edit(void)
{
cout << "edit document " << _name << endl;
}
void save(void)
{
cout << "save document " << _name << endl;
}
void close(void)
{
cout << "close document " << _name << endl;
}
void unedit(void)
{
cout << "unedit document " << _name << endl;
}
void unsave(void)
{
cout << "unsave document " << _name << endl;
}
string getName(void)
{
return _name;
}
};

// application contains docs and act as docs factory as well
class Application
{
private:
list<Document*> _listDoc;
string _appName;
public:
Application(string name): _appName(name) {};
virtual ~Application()
{
for (list<Document*>::iterator it = _listDoc.begin();
it != _listDoc.end(); ++it)
{
delete *it;
*it = NULL;
}
}
public:
bool isExitDocByName(string name)
{
for (list<Document*>::iterator it = _listDoc.begin();
it != _listDoc.end(); ++it)
{
if (0 == ((*it)->getName().compare(name)))
{
return true;
}
}
return false;
}

Document* getDocByName(string name)
{
for (list<Document*>::iterator it = _listDoc.begin();
it != _listDoc.end(); ++it)
{
if (0 == ((*it)->getName().compare(name)))
{
return *it;
}
}

// if not exit , new one & add & return it
Document *doc = new Document(name);
addDoc(doc);
return doc;
}
string getName(void)
{
return _appName;
}
private:
void addDoc(Document* doc)
{
_listDoc.push_back(doc);
}

};

4.最后定义命令请求的调用者Writer

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
// invoker
class Writer
{
public:
Writer(string name) : _name(name) {};
virtual ~Writer()
{
for (list<DocCommandLog*>::iterator it = _listHistoryCmdLog.begin();
it != _listHistoryCmdLog.end(); ++it)
{
delete *it;
*it = NULL;
}
}
public:
class DocCommandLog
{
public:
DocCommand *docCmd;
bool isexecute;
};

void setDocCommand(DocCommand *cmd)
{
_currentCmd = cmd;
}
void doWork(void)
{
_currentCmd->execute();

DocCommandLog *cmdLog = new DocCommandLog();
cmdLog->docCmd = _currentCmd;
cmdLog->isexecute = true;
_listHistoryCmdLog.push_back(cmdLog);
}
void undoWork(void)
{
_currentCmd->unexecute();

DocCommandLog *cmdLog = new DocCommandLog();
cmdLog->docCmd = _currentCmd;
cmdLog->isexecute = false;
_listHistoryCmdLog.push_back(cmdLog);
}
void batWorkByHistoryCmdLog(void)
{
for (list<DocCommandLog*>::iterator it = _listHistoryCmdLog.begin();
it != _listHistoryCmdLog.end(); ++it)
{
if ((*it)->isexecute)
{
(*it)->docCmd->execute();
}
else
{
(*it)->docCmd->unexecute();
}
}
}
public:
string getName(void)
{
return _name;
}
private:
string _name;
DocCommand *_currentCmd;
list<DocCommandLog*> _listHistoryCmdLog;
};

5.测试命令模式:

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

void CommandTest_Doc()
{
Application *app = new Application("VS 2015");
cout << "app name is : " << app->getName() << endl;
Writer *writer = new Writer("tly");
cout << "writer name is: " << writer->getName() << endl;

// 1. open doc
DocCommand *openCmd = new OpenDocCommand(app);
writer->setDocCommand(openCmd);
writer->doWork();
Document *currentOpenDoc = openCmd->getCurrentOpenDoc();
if (NULL == currentOpenDoc)
{
cout << "not open any doc !!!" << endl;
SAFE_RELASE_POINTER(openCmd);
SAFE_RELASE_POINTER(writer);
SAFE_RELASE_POINTER(app);
return;
}

// 2. edit doc
DocCommand *editCmd = new EditDocCommand(currentOpenDoc);
writer->setDocCommand(editCmd);
writer->doWork();

// 3. unedit doc
writer->undoWork();

// 4. save & close doc
DocCommand *macroCmd = new MacroDocCommand();
DocCommand *saveCmd = new SaveDocCommand(currentOpenDoc);
macroCmd->addDocCommand(saveCmd);
DocCommand *closeCmd = new CloseDocCommand(currentOpenDoc);
macroCmd->addDocCommand(closeCmd);
writer->setDocCommand(macroCmd);
writer->doWork();

// 5. bat just doc operate:
cout << "bat history log: " << endl;
writer->batWorkByHistoryCmdLog();

SAFE_RELASE_POINTER(openCmd);
SAFE_RELASE_POINTER(editCmd);
SAFE_RELASE_POINTER(saveCmd);
SAFE_RELASE_POINTER(closeCmd);
SAFE_RELASE_POINTER(macroCmd);
SAFE_RELASE_POINTER(writer);
SAFE_RELASE_POINTER(app);
}

6.运行结果:

app name is : VS 2015
writer name is: tly
please input a name for the doc:
design_pattern
you have enter a doc named: design_pattern
confirm? (Y/N)
y
open document design_pattern
edit document design_pattern
unedit document design_pattern
save document design_pattern
close document design_pattern
bat history log:
please input a name for the doc:
design_pattern
you have enter a doc named: design_pattern
confirm? (Y/N)
y
open document design_pattern
edit document design_pattern
unedit document design_pattern
save document design_pattern
close document design_pattern