访问器模式

访问器模式是一种行为模式,似乎也是一种相当复杂的模式。任何模式都是前人从大量的工程实践经验中总结提炼出来,都对应一类应用场景。那么访问器模式的适用场景是什么呢?

应用场景

我们假设定义了10个类型,满足以下条件:1.每个类型对应很多操作,且操作可能会不断增加;2.自定义类型中的基础数据不会变动。显示,面对这样的场景,我们可以将行为和数据分离开,把变和不变的部分分开,实现解耦。具体应该怎么设计?

代码示例

以下代码是一个简单的示例,定义了一组水果类,同时定义了它的访问类,用户可以根据需求实现不同的访问行为。

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
// fruit.h
#ifndef FRUIT_H_
#define FRUIT_H_

#include "fruit_visitor.h"

class Fruit {
public:
Fruit() = default;
virtual ~Fruit() = default;
virtual void Accept(FruitVisitor* visitor) = 0;
};

class Apple : public Fruit {
public:
virtual void Accept(FruitVisitor* visitor) override {
visitor->VisitApple(this);
}
};

class Watermelon : public Fruit {
public:
virtual void Accept(FruitVisitor* visitor) override {
visitor->VisitWatermelon(this);
}
};

class Mango : public Fruit {
public:
virtual void Accept(FruitVisitor* visitor) override {
visitor->VisitMango(this);
}
};

#endif // FRUIT_H_

//---------------------------------------------------------------------------------------//

// fruit_visitor.h
#ifndef FRUIT_VISITOR_H_
#define FRUIT_VISITOR_H_

class Apple;
class Watermelon;
class Mango;

class FruitVisitor {
public:
FruitVisitor() = default;
virtual ~FruitVisitor() = default;
virtual void VisitApple(Apple* apple) = 0;
virtual void VisitWatermelon(Watermelon* watermelon) = 0;
virtual void VisitMango(Mango* mango) = 0;
};

#endif // FRUIT_VISITOR_H_

//---------------------------------------------------------------------------------------//

// fruit_visitor_hello.h
#ifndef FRUIT_VISITOR_HELLO_H_
#define FRUIT_VISITOR_HELLO_H_

#include <stdio.h>
#include "fruit_visitor.h"
#include "fruit.h"

class FruitVisitorHello : public FruitVisitor {
public:
virtual void VisitApple(Apple* apple) override {
fprintf(stdout, "Hello Apple!\n");
}

virtual void VisitWatermelon(Watermelon* watermelon) override {
fprintf(stdout, "Hello Watermelon!\n");
}

virtual void VisitMango(Mango* mango) override {
fprintf(stdout, "Hello Mango!\n");
}
};

#endif // FRUIT_VISITOR_HELLO_H_

//---------------------------------------------------------------------------------------//

// main.cpp
#include "fruit.h"
#include "fruit_visitor_hello.h"

int main() {
Apple apple;
Watermelon watermelon;
Mango mango;
FruitVisitorHello hello;
apple.Accept(&hello);
watermelon.Accept(&hello);
mango.Accept(&hello);

return 0;
}

模式结构

访问器模式的结构可以拆解为以下几部分:

  • 首先定义一个接受接口,能够接收一个访问接口
  • 具体的数据类型必须继承实现接受接口
  • 定义一个访问接口,申明了对各种数据类型的访问
  • 具体的访问器实现访问接口,并实现具体的行为