C++设计模式一一结构型模式

结构型模式

我们这里介绍两种结构型模式

类对象结构型

  • ADAPTER 适配器模式

对象结构型

  • COMPOSITE 组合模式

适配器模式

适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

适配器可以分为类适配器和对象适配器。

  • 类适配器使用多重继承对一个接口与另一个接口进行匹配。

  • 对象适配器依赖于对象组合

UML图

例子:

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
/* 现在假设你缺少鸭子对象(叫声为Quack,飞行输出”I’m flying !”),
* 想用一些火鸡对象(叫声为”Gobble gobble” 飞行输出”I’m flying a short distance!”)来冒充。
* 显而易见,因为火鸡的接口(行为)不同,所以我们不能公然拿来使用
*/
#include <iostream>
using namespace std;
// 定义鸭子类
class Duck {
public:
virtual void quack() {}; //嘎嘎声
virtual void fly() {};
};
// 定义绿头鸭
class MallardDuck : public Duck {
public:
void quack() {
cout << "Quack" << endl;
}
void fly() {
cout << "I'm flying" << endl;
}
};
// 定义火鸡
class Turkey {
public:
virtual void gobble() {};
virtual void fly() {};
};
// 定义野火鸡
class WildTurkey : public Turkey {
public:
void gobble() {
cout << "Gobble gobble" << endl;
}
void fly() {
cout << "I'm flying a short distance" << endl;
}
};
// 定义火鸡适配器
class TurkeyAdapter : public Duck {
public:
TurkeyAdapter(Turkey* tur) : turkey(tur) {}
void quack() {
turkey->gobble();
}
void fly() {
turkey->fly();
}
private:
Turkey* turkey;
};
int main() {
Duck *duck = new MallardDuck();
duck->quack();
duck->fly();
Duck *turkeyAdapter = new TurkeyAdapter(new WildTurkey());
turkeyAdapter->quack();
turkeyAdapter->fly();
return 0;
}

测试结果:

适配器和装饰者模式比较

  • 适配器:将一个接口转成另一个接口。包装某些对象,让它们的接口看起来不像自己而像别的东西。

  • 装饰者:不改变接口,但加入责任。将对象包装起来,让新行为加入类中

组合模式

组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

这个模式能够创建一个树形结构,在同一个结构中处理嵌套菜单和菜单项组。通过菜单和项放在相同结构中,我们创建了一个“整体/部分”层次结构,即由菜单和菜单项组成的对象树。

使用组合结构,我们能把相同的操作应用在组合和个别对象上。
换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

UML图

例子:

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* 我们希望在午餐餐单中增加一份甜点餐单,
* 也就是说希望能让甜点餐单变成午餐餐单的一个元素
*
* 我们可以用组合模式解决这个问题:
* 一开始我们创建一个组件接口作为餐单和菜单项的共同接口,
* 让我们能够用统一的做法来处理菜单和菜单项。
* 换句话说,我们可以针对菜单或菜单项调用相同的方法。
* 然后实现菜单项和组合菜单组件,以及他们各自的方法。
*/
#include <iostream>
#include <vector>
#include <list>
#include <string>
using namespace std;
//菜单和菜单项共同的组件
class MenuComponent {
public:
virtual void add(MenuComponent* menuComponent) {
// 但gcc(4.8.1)中, 需要使用标准异常进行处理
logic_error ex("add error!");
throw exception(ex);
}
virtual void remove(MenuComponent* menuComponent) {
logic_error ex("remove error!");
throw exception(ex);
}
virtual MenuComponent* getChild(int i) {
logic_error ex("getChild error!");
throw exception(ex);
}
virtual string getName() {
logic_error ex("getName error!");
throw exception(ex);
}
virtual string getDescription() {
logic_error ex("getDescription error!");
throw exception(ex);
}
virtual double getPrice() {
logic_error ex("getPrice error!");
throw exception(ex);
}
virtual void print() {
logic_error ex("getPrice error!");
throw exception(ex);
}
};
//菜单项类
class MenuItem : public MenuComponent {
public:
MenuItem() {}
MenuItem(string na, string descri, double pric) {
name = na;
description = descri;
price = pric;
}
string getName() {
return name;
}
string getDescription() {
return description;
}
double getPrice() {
return price;
}
void print() {
cout << " " << getName() << ", " << getPrice() << " ---" << getDescription() << endl;
}
private:
string name;
string description;
double price;
};
// 组合菜单类
class Menu : public MenuComponent {
public:
Menu(string nam, string descri) {
name = nam;
description = descri;
}
void add(MenuComponent* pMenuComponent) {
pMenuComponents.push_back(pMenuComponent);
}
void remove(MenuComponent* pMenuComponent) {
vector<MenuComponent*>::iterator iter = pMenuComponents.begin();
for (; iter != pMenuComponents.end(); ++iter) {
if (*iter == pMenuComponent) {
pMenuComponents.erase(iter);
}
}
}
MenuComponent* getChild(int i) {
return pMenuComponents[i];
}
string getName() {
return name;
}
string getDescription() {
return description;
}
void print() {
cout << endl << getName() << ", " << getDescription() << endl << "------------------" << endl;
vector<MenuComponent*>::iterator iter = pMenuComponents.begin();
while (iter != pMenuComponents.end()) {
MenuComponent* pMenuComponent = *iter;
pMenuComponent->print();
++iter;
}
}
private:
vector<MenuComponent*> pMenuComponents;
string name;
string description;
};
// 服务生类
class Waitress {
public:
Waitress(MenuComponent* all_Menus) {
allMenus = all_Menus;
}
void printMenu() {
allMenus->print();
}
private:
MenuComponent* allMenus;
};
int main() {
MenuComponent* pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU", "Breakfast");
MenuComponent* dinerMenu = new Menu("Diner MENU", "Lunch");
MenuComponent* dessertMenu = new Menu("DESSERT MENU","Dessert of coure!");
MenuComponent* allMenus = new Menu("ALL Menus", "All menus combined");
allMenus->add(pancakeHouseMenu);
allMenus->add(dinerMenu);
dinerMenu->add(new MenuItem("Pasta", "Spaheti with Sauce", 3.89));
dinerMenu->add(dessertMenu);
dessertMenu->add(new MenuItem("Apple Pie", "Apple pie with a cruse", 1.59));
Waitress* waitress = new Waitress(allMenus);
waitress->printMenu();
return 0;
}

测试结果: