0%

设计模式之命令模式和访问模式

设计模式基础(14):命令模式&访问模式

包含命令模式&访问模式两种模式中的C++示例代码、面向的问题、图解两种模式核心思想

命令模式

面向的需求

  • 在软件构建的过程中,“行为请求者”和“行为实现者”通常是一种紧耦合。在一些业务场景中希望解耦这种关系。将一组行为抽象为对象。

示例代码

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
#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Command
{
public:
virtual void execute() = 0;
};

class ConcreteCommand1 : public Command
{
string arg;
public:
ConcreteCommand1(const string & a) : arg(a) {}
void execute() override
{
cout<< "#1 process..."<<arg<<endl;
}
};

class ConcreteCommand2 : public Command
{
string arg;
public:
ConcreteCommand2(const string & a) : arg(a) {}
void execute() override
{
cout<< "#2 process..."<<arg<<endl;
}
};
class MacroCommand : public Command
{
vector<Command*> commands;
public:
void addCommand(Command *c) { commands.push_back(c); }
void execute() override
{
for (auto &c : commands)
{
c->execute();
}
}
};

int main()
{

ConcreteCommand1 command1(receiver, "Arg ###");
ConcreteCommand2 command2(receiver, "Arg $$$");

MacroCommand macro;
macro.addCommand(&command1);
macro.addCommand(&command2);

macro.execute();

}

代码思想分析

访问模式

  • 这样的好处是什么?
  • 将请求(命令)封装为一个对象,从而你可以用不同的请求对客户进行参数化;支持更多更灵活的面向对象的操作。

关键点

  • 目前这种直接封装命令的方案逐渐弃用,其思想更多是通过函数对象来实现,如仿函数。

访问模式

面向的需求

当需要对已经存在的类内部做进一步的功能扩展,如何在保证代码的复用性上为其增加功能。

示例代码

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

class Visitor;
class Element
{
public:
virtual void accept(Visitor& visitor) = 0; //第一次多态辨析
virtual ~Element(){}
};

class ElementA : public Element
{
public:
void accept(Visitor &visitor) override {
visitor.visitElementA(*this);
}


};

class ElementB : public Element
{
public:
void accept(Visitor &visitor) override {
visitor.visitElementB(*this); //第二次多态辨析
}

};

class Visitor{
public:
virtual void visitElementA(ElementA& element) = 0;
virtual void visitElementB(ElementB& element) = 0;

virtual ~Visitor(){}
};

//==================================

//扩展1
class Visitor1 : public Visitor{
public:
void visitElementA(ElementA& element) override{
cout << "Visitor1 is processing ElementA" << endl;
}

void visitElementB(ElementB& element) override{
cout << "Visitor1 is processing ElementB" << endl;
}
};

//扩展2
class Visitor2 : public Visitor{
public:
void visitElementA(ElementA& element) override{
cout << "Visitor2 is processing ElementA" << endl;
}

void visitElementB(ElementB& element) override{
cout << "Visitor2 is processing ElementB" << endl;
}
};




int main()
{
Visitor2 visitor;
ElementB elementB;
elementB.accept(visitor);// double dispatch

ElementA elementA;
elementA.accept(visitor);


return 0;
}

代码思想分析

访问模式
分析

  • 借助一个visitor来捕获原有的对象类型,在visitor中增加具体的功能
  • 核心技术逻辑double dispatch。
  • 先根据Base基类的指针对象,多态确定是谁调用的accept。
  • 再根据accept传入的Visitor基类指针,多态确定具体是哪一个visitor下功能。

关键点

  • 一定要注意到Base的子类类型数目一定要确定,因为这涉及到模式的稳定性。
  • Double Dispatch的逻辑调用关系