命令模式

命令模式在 C++ 代码中很常见,大部分情况下, 它被用于代替包含行为的参数化 UI 元素的回调函数。我不知道你是否阅读过任意网络库,这边就以 Muduo 网络库举例说明:

命令模式1.png

用户传递的 某个回调函数(往往是读操作和写操作)通过层层传递,最终会被 Channel 这个调用者执行,但是用户不必关心谁来执行这个回调函数(即用户发出的命令),只需要发出命令即可。可以看出,用户发出的命令会被存储起来,实际的执行也不是由 TcpServer 执行。

因此,我们讲命令模式可以对发送者和接收者(执行者)完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。

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
#include <iostream>
#include <map>
#include <list>
using namespace std;

// 由于 存在不同的命令,因此需要将 命令类 设置为 抽象基类

class Command {
public:
virtual string name() = 0;
virtual void Excute() = 0;
virtual ~Command(){}
};

// 命令执行者
class Invoker {
public:
void makeGBJD() {
cout << "制作 宫保鸡丁" << endl;
}

void makeCQXM() {
cout << "制作 重庆小面" << endl;
}

void makeMCKR() {
cout << "制作 梅菜扣肉" << endl;
}
};

// 每个命令会被封装为一个对象
class GBJDCommand : public Command {
public:
GBJDCommand(Invoker* inv) :invoker_(inv){}
void Excute() override {
invoker_->makeGBJD();
}
string name() override {
return "GBJD";
}
virtual ~GBJDCommand() {};
protected:
Invoker* invoker_;
};

class CQXMCommand : public Command {
public:
CQXMCommand(Invoker* inv) :invoker_(inv) {}
void Excute() override {
invoker_->makeCQXM();
}
string name() override {
return "CQXM";
}
virtual ~CQXMCommand() {};
protected:
Invoker* invoker_;
};

class MCKRCommand : public Command {
public:
MCKRCommand(Invoker* inv) :invoker_(inv) {}
void Excute() override {
invoker_->makeMCKR();
}
string name() override {
return "MCKR";
}
virtual ~MCKRCommand() {};
protected:
Invoker* invoker_;
};


// 命令传递者(接收者)
class Transmitter {
public:
// 下达命令
void give_order(int uuid,Command* command) {
cout << "uuid = " << uuid << "| 下达命令 = " << command->name() <<endl;

auto its = orders_.find(uuid);
if (its != orders_.end()) {
orders_[uuid].push_back(command);
}
else {
list<Command*> data = { command };
orders_[uuid] = data;
}

}
// 撤销命令
void cancel_order(int uuid, Command* command) {
auto its = orders_.find(uuid);
if (its != orders_.end()) {
cout << "uuid = " << uuid << "| 取消命令 = " << command->name() << endl;
orders_[uuid].remove(command);
}
}

// 提交命令
void submit_order() {
for (auto order : orders_) {
for (auto conmand : order.second) {
conmand->Excute();
}
}
orders_.clear();
}

private:
map<int, list<Command*>> orders_; // key 是用户id,value 是用户下达的命令
};

客户端测试代码:

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
int main(int argc,char* argv[]) {

Invoker* invoker = new Invoker();
Transmitter* trans = new Transmitter();

// 创建一个命令列表
GBJDCommand* gbjd = new GBJDCommand(invoker);
CQXMCommand* cqxm = new CQXMCommand(invoker);
MCKRCommand* mkqr = new MCKRCommand(invoker);

// 用户可以下达命令了,通过传递命令的人

trans->give_order(1, gbjd);
trans->give_order(1, mkqr);
trans->cancel_order(1, mkqr);
trans->submit_order();

trans->give_order(2, cqxm);
trans->give_order(2, gbjd);
trans->give_order(2, mkqr);
trans->cancel_order(2, gbjd);
trans->submit_order();

return 0;
}

/*
uuid = 1| 下达命令 = GBJD
uuid = 1| 下达命令 = MCKR
uuid = 1| 取消命令 = MCKR
制作 宫保鸡丁
uuid = 2| 下达命令 = CQXM
uuid = 2| 下达命令 = GBJD
uuid = 2| 下达命令 = MCKR
uuid = 2| 取消命令 = GBJD
制作 重庆小面
制作 梅菜扣肉
*/

想必各位也看出来了,如果我们需要更多的命令,那就需要添加更多的命令类,同时还要在 Invoker 类中添加实际的执行代码。