设计模式之命令模式
命令模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。其UML类图如下:
该模式主要是为了隔离请求和实际执行者之间解除。就是解耦和,所有的请求统一有一个类负责,而该类负责管理这些请求(添加请求、撤销请求之类的)。上图种Invoker负责接受和管理各种命令。然后有Invoker统一像Receiver发起请求。所有类型的请求都封装在Command中了。这样做,发起命令者根本不用知道是谁来做这个事情的。比如餐厅点餐,客人无论是点餐还是撤销还是有特殊要求都只用跟服务员说就可以了,而并不用和实际的做菜的人说。示例代码如下:
1 // CommandModel.h文件
2 #pragma once
3 #include <iostream>
4 #include <vector>
5 #include <algorithm>
6
7 // 烤肉师傅
8 class BarbecueMaster
9 {
10 public:
11 void MakeMutton()
12 {
13 std::cout << "烤羊腿喽" << std::endl;
14 }
15 void MakeChiken()
16 {
17 std::cout << "烤鸡肉喽" << std::endl;
18 }
19 };
20 // 命令类
21 class Command
22 {
23 protected:
24 BarbecueMaster * m_master;
25 public:
26 Command(BarbecueMaster * p)
27 {
28 m_master = p;
29 }
30 virtual void executeCmd() = 0;
31 };
32
33 class CommandMutton : public Command
34 {
35 public:
36 CommandMutton(BarbecueMaster * p) : Command(p) {}
37 void executeCmd()
38 {
39 m_master->MakeMutton();
40 }
41 };
42
43 class CommandChiken : public Command
44 {
45 public:
46 CommandChiken(BarbecueMaster * p) : Command(p) {}
47 void executeCmd()
48 {
49 m_master->MakeChiken();
50 }
51 };
52 // 服务员
53 class Waiter
54 {
55 private:
56 std::vector<Command *> m_vec;
57 public:
58 ~Waiter()
59 {
60 for (auto it = m_vec.begin(); it != m_vec.end(); it++)
61 {
62 delete(*it);
63 }
64 m_vec.clear();
65 }
66 void add(Command * p)
67 {
68 m_vec.push_back(p);
69 }
70 void remove(Command * p)
71 {
72 auto it = find(m_vec.begin(), m_vec.end(), p);
73 if (it != m_vec.end())
74 m_vec.erase(it);
75 }
76 void submitCmd()
77 {
78 for (auto it = m_vec.cbegin(); it != m_vec.cend(); it++)
79 {
80 (*it)->executeCmd();
81 }
82 }
83 };
测试代码如下:
1 #include <iostream>
2 #include "CommandModel.h"
3
4 int main()
5 {
6 using namespace std;
7 // 命令模式
8 Waiter * pWaiter = new Waiter();
9 BarbecueMaster * pMaster = new BarbecueMaster();
10 pWaiter->add(new CommandChiken(pMaster));
11 pWaiter->add(new CommandMutton(pMaster));
12 pWaiter->submitCmd();
13 delete pMaster;
14 delete pWaiter;
15
16 getchar();
17 return 0;
18 }
测试结果如下图:
命令模式和代理模式的区别:
从使用角度上感觉这两种模式实现的功能很像。但从具体实现上来讲,命令模式侧重点在于对命令的封装和对命令的管理,在于对命令的发起者和命令的世界操作者之间解耦和。属于行为模式的一种。而代理模式只是实现了实际可被访问功能的接口,代理模式并没有对命令或请求的管理。
命令模式和外观模式的区别:
命令模式和代理模式的UML类图也是很相似的。从宏观的角度上理解它们之间实现的功能也非常相似。不过外观模式更注重的是对子系统功能的封装,它们之间的外观类和子系统中类的接口并不一样。命令模式并没有对Receiver功能的封装,命令模式侧重的是命令和命令执行者之间的解耦和。不过这两种模式一起使用则非常方便。命令模式的中的Receiver可以是一个Facade,是一个子系统上的一个接口。而一个Facade内部的各个接口实现的则也可以封装成为一各个Command等。