Skip to content

Commit 4aa96cb

Browse files
committed
add command
1 parent 7688bba commit 4aa96cb

File tree

8 files changed

+383
-1
lines changed

8 files changed

+383
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
[责任链模式 Chain of Responsibility](doc/15-责任链.md)
4242

43-
命令模式 Command
43+
[命令模式 Command](doc/16-命令.md)
4444

4545
解释器模式 Interpreter
4646

code/15_command/15_command.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29215.179
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15_command", "15_command.vcxproj", "{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|x64 = Debug|x64
11+
Debug|x86 = Debug|x86
12+
Release|x64 = Release|x64
13+
Release|x86 = Release|x86
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Debug|x64.ActiveCfg = Debug|x64
17+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Debug|x64.Build.0 = Debug|x64
18+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Debug|x86.ActiveCfg = Debug|Win32
19+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Debug|x86.Build.0 = Debug|Win32
20+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Release|x64.ActiveCfg = Release|x64
21+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Release|x64.Build.0 = Release|x64
22+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Release|x86.ActiveCfg = Release|Win32
23+
{37C48A70-F43B-4ED9-A0A0-377C11BF00A6}.Release|x86.Build.0 = Release|Win32
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {2AA1AD58-F91F-45CF-ADCB-DDC21BA0091C}
30+
EndGlobalSection
31+
EndGlobal

code/15_command/client.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "command_types.h"
2+
3+
int main() {
4+
5+
Receiver* reciver1 = new MiCenter;
6+
Receiver* reciver2 = new ZigBee;
7+
8+
list<Command*> list;
9+
10+
Command* command1 = new SendMessage(reciver1,true);
11+
Command* command2 = new TurnOn(reciver2);
12+
Command* command3 = new SendMessage(reciver1, false);
13+
Command* command4 = new TurnOff(reciver2);
14+
Command* command5 = new TurnOff(reciver2);
15+
list.push_back(command1);
16+
list.push_back(command2);
17+
list.push_back(command3);
18+
list.push_back(command4);
19+
list.push_back(command5);
20+
21+
Invoker* invoker = new BodySensor(list);
22+
invoker->invoke();
23+
return 0;
24+
}

code/15_command/command_types.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
#include <iostream>
3+
#include <list>
4+
using namespace std;
5+
6+
class Command {
7+
public:
8+
virtual void execute() = 0;
9+
};
10+
11+
class Receiver {
12+
public:
13+
virtual void action() = 0;
14+
};
15+
16+
class Invoker {
17+
public:
18+
virtual void invoke() = 0;
19+
};
20+
21+
22+
class MiCenter : public Receiver {
23+
public:
24+
void action() {
25+
cout << "[MiCenter]Stored detect people event" << endl;
26+
}
27+
};
28+
29+
class ZigBee :public Receiver {
30+
public:
31+
ZigBee() :state(false) {}
32+
void action() {
33+
if (state) {
34+
cout << "Current state is turn on, so turn off now.\n" << endl;
35+
}
36+
else {
37+
cout << "Current state is turn off, so turn on now.\n" << endl;
38+
}
39+
state = !state;
40+
}
41+
bool getState() {
42+
return state;
43+
}
44+
private:
45+
bool state;
46+
};
47+
48+
49+
class SendMessage : public Command {
50+
public:
51+
SendMessage(Receiver* receiver,bool hasPerson) :m_hasPerson(hasPerson),m_receiver(receiver) {
52+
53+
}
54+
void execute() {
55+
cout << (m_hasPerson?"Detect people now.":"Not detect people in recent minutes.")<< endl;
56+
if (m_receiver)
57+
m_receiver->action();
58+
}
59+
private:
60+
bool m_hasPerson;
61+
Receiver* m_receiver;
62+
};
63+
64+
65+
class TurnOn : public Command {
66+
public:
67+
TurnOn(Receiver* receiver) :m_receiver(receiver) {
68+
69+
}
70+
void execute() {
71+
if (m_receiver) {
72+
ZigBee* receiver = static_cast<ZigBee*>(m_receiver);
73+
if (receiver && receiver->getState() == false)
74+
m_receiver->action();
75+
else
76+
cout << "Reciver[ZigBee] already turn on, so ignore" << endl;
77+
}
78+
79+
}
80+
private:
81+
Receiver* m_receiver;
82+
};
83+
84+
class TurnOff : public Command {
85+
public:
86+
TurnOff(Receiver* receiver) :m_receiver(receiver) {
87+
88+
}
89+
void execute() {
90+
if (m_receiver) {
91+
ZigBee* receiver = static_cast<ZigBee*>(m_receiver);
92+
if (receiver && receiver->getState())
93+
m_receiver->action();
94+
else
95+
cout << "Reciver[ZigBee] already turn off, so ignore" << endl;
96+
}
97+
}
98+
private:
99+
Receiver* m_receiver;
100+
};
101+
102+
103+
104+
class BodySensor : public Invoker {
105+
public:
106+
BodySensor(list<Command*>& cmdlist):cmdlist_ptr(cmdlist){}
107+
108+
void invoke() {
109+
list<Command*>::const_iterator iter = cmdlist_ptr.begin();
110+
while (iter != cmdlist_ptr.end()) {
111+
(*iter)->execute();
112+
iter++;
113+
}
114+
}
115+
private:
116+
list<Command*> cmdlist_ptr;
117+
};

code/15_command/result.png

8.41 KB
Loading

doc/16-命令.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# 命令
2+
3+
将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。
4+
5+
6+
## UML
7+
8+
* Command(抽象命令类): 是一个抽象类,声明了用于执行命令的接口execute()
9+
* ConcreteCommnad(具体命令类): 具体的命令类,实现了执行命令的接口execute(),它对应具体的接收者对象,将接收者(Receiver)的动作action()绑定其中。在execu()方法中将调用接收者的动作action()
10+
* Invoker(调用者): 请求的发送者,通过命令对象来执行请求。一个调用者不需要在设计时确定其接收者,所以调用者通过聚合,与命令类产生关联
11+
* Receiver(接收者): 实现处理请求的具体操作(action)
12+
13+
![figure15_command](img/figure15_command.png)
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+
[code](../code/15_command)
41+
42+
```c++
43+
// command_types.h
44+
#pragma once
45+
#include <iostream>
46+
#include <list>
47+
using namespace std;
48+
49+
class Command {
50+
public:
51+
virtual void execute() = 0;
52+
};
53+
54+
class Receiver {
55+
public:
56+
virtual void action() = 0;
57+
};
58+
59+
class Invoker {
60+
public:
61+
virtual void invoke() = 0;
62+
};
63+
64+
class MiCenter : public Receiver {
65+
public:
66+
void action() {
67+
cout << "[MiCenter]Stored detect people event" << endl;
68+
}
69+
};
70+
71+
class ZigBee :public Receiver {
72+
public:
73+
ZigBee() :state(false) {}
74+
void action() {
75+
if (state) {
76+
cout << "Current state is turn on, so turn off now.\n" << endl;
77+
}
78+
else {
79+
cout << "Current state is turn off, so turn on now.\n" << endl;
80+
}
81+
state = !state;
82+
}
83+
bool getState() {
84+
return state;
85+
}
86+
private:
87+
bool state;
88+
};
89+
90+
class SendMessage : public Command {
91+
public:
92+
SendMessage(Receiver* receiver,bool hasPerson) :m_hasPerson(hasPerson),m_receiver(receiver) {
93+
94+
}
95+
void execute() {
96+
cout << (m_hasPerson?"Detect people now.":"Not detect people in recent minutes.")<< endl;
97+
if (m_receiver)
98+
m_receiver->action();
99+
}
100+
private:
101+
bool m_hasPerson;
102+
Receiver* m_receiver;
103+
};
104+
105+
class TurnOn : public Command {
106+
public:
107+
TurnOn(Receiver* receiver) :m_receiver(receiver) {
108+
109+
}
110+
void execute() {
111+
if (m_receiver) {
112+
ZigBee* receiver = static_cast<ZigBee*>(m_receiver);
113+
if (receiver && receiver->getState() == false)
114+
m_receiver->action();
115+
else
116+
cout << "Reciver[ZigBee] already turn on, so ignore" << endl;
117+
}
118+
119+
}
120+
private:
121+
Receiver* m_receiver;
122+
};
123+
124+
class TurnOff : public Command {
125+
public:
126+
TurnOff(Receiver* receiver) :m_receiver(receiver) {
127+
128+
}
129+
void execute() {
130+
if (m_receiver) {
131+
ZigBee* receiver = static_cast<ZigBee*>(m_receiver);
132+
if (receiver && receiver->getState())
133+
m_receiver->action();
134+
else
135+
cout << "Reciver[ZigBee] already turn off, so ignore" << endl;
136+
}
137+
}
138+
private:
139+
Receiver* m_receiver;
140+
};
141+
142+
class BodySensor : public Invoker {
143+
public:
144+
BodySensor(list<Command*>& cmdlist):cmdlist_ptr(cmdlist){}
145+
146+
void invoke() {
147+
list<Command*>::const_iterator iter = cmdlist_ptr.begin();
148+
while (iter != cmdlist_ptr.end()) {
149+
(*iter)->execute();
150+
iter++;
151+
}
152+
}
153+
private:
154+
list<Command*> cmdlist_ptr;
155+
};
156+
```
157+
158+
```c++
159+
// client.cpp
160+
#include "command_types.h"
161+
162+
int main() {
163+
164+
Receiver* reciver1 = new MiCenter;
165+
Receiver* reciver2 = new ZigBee;
166+
167+
list<Command*> list;
168+
169+
Command* command1 = new SendMessage(reciver1,true);
170+
Command* command2 = new TurnOn(reciver2);
171+
Command* command3 = new SendMessage(reciver1, false);
172+
Command* command4 = new TurnOff(reciver2);
173+
Command* command5 = new TurnOff(reciver2);
174+
list.push_back(command1);
175+
list.push_back(command2);
176+
list.push_back(command3);
177+
list.push_back(command4);
178+
list.push_back(command5);
179+
180+
Invoker* invoker = new BodySensor(list);
181+
invoker->invoke();
182+
return 0;
183+
}
184+
```

doc/img/figure15_command.png

14.4 KB
Loading

doc/uml/15_command.pu

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@startuml "figure15_command"
2+
caption figure 16: Command
3+
4+
class Command{
5+
+ execute(): void
6+
}
7+
8+
class ConcreteCommand{}
9+
10+
class Invoker{
11+
- commandList: List<Command>
12+
+ invoke(): void
13+
}
14+
15+
class Receiver{
16+
+ action(): void
17+
}
18+
19+
class Client{}
20+
21+
Command <|-- ConcreteCommand
22+
Invoker o-right- Command
23+
Receiver <-right- ConcreteCommand
24+
Client .up.> Invoker
25+
Client ..> ConcreteCommand
26+
@enduml

0 commit comments

Comments
 (0)