1. 设计模式三原则

在进行程序设计的时候,要尽可能地保证程序的可扩展性、可维护性和可读性,所以需要使用一些设计模式,这些设计模式都遵循了以下三个原则。

1.1 单一职责原则

C++面向对象三大特性之一的封装指的就是将单一事物抽象出来组合成一个类,所以我们在设计类的时候每个类中处理的是单一事物而不是某些事物的集合。

设计模式中所谓的单一职责原则:就是对一个类而言,应该仅有一个引起它变化的原因,其实就是将这个类所承担的职责单一化。

1.2 开放封闭原则

开放封闭原则:指的是软件实体(类、模块、函数等)可以扩展,但是不可以修改。也就是说对于扩展是开放的,对于修改是封闭的。

开放封闭原则是面向对象设计的核心所在,这样可以给我们设计出的程序带来巨大的好处,使其可维护性、可扩展性、可复用性、灵活性更好。

1.3 依赖倒转原则

关于依赖倒转原则,对应的是两条非常抽象的描述:

  • 高层模块不应该依赖低层模块,两个都应该依赖抽象。
    • 高层模块:可以理解为上层应用,就是业务层的实现
    • 低层模块:可以理解为底层接口,比如封装好的API、动态库等
    • 抽象:指的就是抽象类或者接口,在C++中没有接口,只有抽象类
  • 抽象不应该依赖细节,细节应该依赖抽象。
    • 里氏代换原则:就是子类类型必须能够替换掉它们的父类类型。

2. 单例模式

在一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个唯一实例向其他模块提供数据的全局访问,这种模式就叫单例模式。单例模式的典型应用就是任务队列。

在实现一个单例模式的类的时候,有两种处理模式:

  • 饿汉模式
  • 懒汉模式

2.1 饿汉模式

饿汉模式:定义类的时候就创建了单例实例,创建出来后,什么时候用,时候什么就调用静态的成员函数(得到单例对象)。

缺点:浪费空间

优点:在多线程的场景下,饿汉模式是没有线程安全问题的(多线程可以同时访问这个单例的对象)

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
class TaskQueue {      //通过类名来得到的对象是静态的,通过类名访问类里面的属性和方法,这个属性和方法是静态的
public:
//堵死在外部创建对象的方法,防止通过拷贝构造或赋值操作来创建多个实例
TaskQueue(const TaskQueue& t) = delete; //删除了拷贝构造函数
TaskQueue& operator = (const TaskQueue& t) = delete; //赋值运算符重载函数
//静态的公共成员函数,把唯一的单例对象返回给调用者
static TaskQueue* getInstance() {
return m_taskQ;
}
void print() {
cout << "我是单例对象的一个成员函数..." << endl;
}

private:
TaskQueue() = default; //定义了一个无参构造,它与默认的无参构造具有相同的行为
//TaskQueue(const TaskQueue& t) = default;
//TaskQueue& operator = (const TaskQueue& t) = default;
//只能通过类名访问静态属性或方法
static TaskQueue* m_taskQ; //该静态成员指针只能通过静态成员方法访问
};
//类里面的静态成员变量使用前,必须在类的外部对其进行初始化(不能在内部进行初始化)
TaskQueue* TaskQueue::m_taskQ = new TaskQueue; //类的作用域下,可以访问类的私有成员

int main(){
TaskQueue* taskQ = TaskQueue::getInstance();
taskQ->print();
}

2.2 懒汉模式

懒汉模式:什么时候使用这个单例对象,在使用的时候再去创建对应的实例。

优点:节省空间

缺点:在多线程的场景下,懒汉模式是有线程安全问题的(若干个线程同时访问单例的实例,会出问题)。

  • 解决办法:通过互斥锁,阻塞线程,依次访问这个单例对象,就可以避免在懒汉模式下,多线程同时访问单例对象而创建出多了类的实例这种问题

双重检查锁定:如果没有第9行的判断,该方法对程序执行的效率就很低,因为不管什么时候,多个线程在访问单例对象的时候(执行getInstance()函数),都是顺序访问的。但通过双重检查锁定可以解决这个问题,只有第一次的时候,多个线程是线性访问,当后面再访问该函数时(m_taskQ指针被实例化处理之后),多个线程就是并行访问了,因为第9行代码判断为false,直接返回该实例对象即可。

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
class TaskQueue
{
public:
// = delete 代表函数禁用, 也可以将其访问权限设置为私有
TaskQueue(const TaskQueue& obj) = delete;
TaskQueue& operator=(const TaskQueue& obj) = delete;
static TaskQueue* getInstance()
{
if (m_taskQ == nullptr)
{
m_mutex.lock();
if (m_taskQ == nullptr)
{
m_taskQ = new TaskQueue;
}
m_mutex.unlock();
}
return m_taskQ;
}
private:
TaskQueue() = default;
static TaskQueue* m_taskQ;
static mutex m_mutex; //像这种不需要初始化的,也需要在外部进行申明,因为它是静态的成员
};
TaskQueue* TaskQueue::m_taskQ = nullptr; //开始先置为空,什么时候使用,什么时候就实例化对象出来
mutex TaskQueue::m_mutex;

上面程序第14行代码对应的机器指令有3条,第1条是创建一块内存(无数据);第2条是创建TaskQueue对象,并吧数据写入到创建的内存里面;第3条是将创建的有效地址传给m_taskQ指针。在底层执行程序的时候,可能会对这些指令做重排,就有可能是执行的顺序是132,在还没有执行第2条时,就先将内存地址传给了指针,这时的指针不为空,但没有TaskQueue对象,同一时刻的其它线程调用该函数就会直接返回指针使用,就造成了系统崩溃。所以下面可以通过原子变量来解决这个问题。

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
class TaskQueue {
public:
TaskQueue(const TaskQueue& t) = delete;
TaskQueue& operator = (const TaskQueue& t) = delete;
//静态的公共成员函数,把唯一的单例对象返回给调用者
static TaskQueue* getInstance() {
TaskQueue* task = m_taskQ.load(); //从原子变量里面加载这个任务队列的实例
if (task == nullptr) { //通过双重检查锁定来避免访问效率低的情况(顺序访问)
m_mutex.lock(); //加锁
task = m_taskQ.load(); //通过原子变量加载实例对象
if (task == nullptr) {
task = new TaskQueue; //使用时创建,创建单例实例--->底层指执行这句话的顺序不一样(对应底层3条语句)-->需要用原子变量进行管理
m_taskQ.store(task); //将创建的实例存储起来,保存在原子变量内部
}
m_mutex.unlock();
}
return task;
}
void print() {
cout << "我是单例对象的一个成员函数..." << endl;
}

private:
TaskQueue() = default; //定义了一个无参构造,它与默认的无参构造具有相同的行为
static mutex m_mutex; //静态变量互斥锁--->需要在类的外面进行一个声明
static atomic<TaskQueue*>m_taskQ; //通过原子变量把类的实例对象保存起来,保存到了指针里面
};
//类里面的静态成员变量使用前,必须在类的外部对其进行初始化(不能在内部进行初始化)
//TaskQueue* TaskQueue::m_taskQ = nullptr;
atomic<TaskQueue*> TaskQueue::m_taskQ; //
mutex TaskQueue::m_mutex;

当然,也可以使用静态的局部对象解决线程安全问题。

3. 工厂模式

3.1 简单工厂模式

下面程序就是简单工厂模式实现的例子,首先创建一个产品类作为父类,里面只需要定义一些虚函数即可,供子类继承实现。然后创建一个工厂类,里面实现父类指针指向子类对象,以达到多态的效果。

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
//产品类的父亲 ---> 人造恶魔果实
class AbstractSmile {
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {} //虚的析构函数,可以完全清除子类的内存
};

class SheepSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability() override {
cout << "将手臂变成绵羊角的招式--巨羊角" << endl;
}
};

class LionSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability() override {
cout << "火遁 -- 豪火球之术..." << endl;
}
};

class BatSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability() override {
cout << "声纳-引剑之万归宗..." << endl;
}
};

//定义工厂类
enum class Type :char {Sheep,Lion,Bat}; //定义了一个枚举类(enum class)Type,并指定了其基础类型为 char。在这个枚举类中,有三个枚举常量:Sheep、Lion和Bat
class SmileFactory{
public:
AbstractSmile* createSmile(Type type){ //父类指针指向了子类对象,实现多态
AbstractSmile* ptr = nullptr;
switch (type) {
case Type::Sheep:
ptr = new SheepSmile;
break;
case Type::Lion:
ptr = new LionSmile;
break;
case Type::Bat:
ptr = new BatSmile;
break;
default:
break;
}
return ptr;
}
};

int main(){
SmileFactory factory; //创建一个工厂对象
AbstractSmile* obj = factory.createSmile(Type::Lion);
obj->transform();
obj->ability();
}

3.2 工厂模式

在上面的简单工厂模式中是只创建了一个工厂类,用于生产需要的对象,但是这种方式有一个弊端,它违反了设计模式中的开放封闭原则,即如果想要生成更多的人造恶魔果实,那么就需要在工厂函数的switch语句中添加更多的case,很明显这违背了封闭原则。所以我们可以使用工厂模式很完美的解决上述的问题。总的来说,就是简单工厂模式是只有一个工厂类,而工厂模式是有很多的工厂类:

  • 一个基类,包含一个虚工厂函数,用于实现多态。
  • 多个子类,重写父类的工厂函数。每个子工厂类负责生产一种恶魔果实,这相当于再次解耦,将工厂类的职责再次拆分、细化,如果要生产新品种的恶魔果实,那么只需要添加对应的工厂类,无需修改原有的代码。
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
//工厂模式相对于简单工厂模式来说,对类的扩展更方便了
//产品类的父亲 ---> 人造恶魔果实
class AbstractSmile {
public:
virtual void transform() = 0;
virtual void ability() = 0;
virtual ~AbstractSmile() {} //虚的析构函数,可以完全清除子类的内存
};

class SheepSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 山羊人形态..." << endl;
}
void ability() override {
cout << "将手臂变成绵羊角的招式 -- 巨羊角" << endl;
}
};

class LionSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 狮子人形态..." << endl;
}
void ability() override {
cout << "火遁 -- 豪火球之术..." << endl;
}
};

class BatSmile :public AbstractSmile {
public:
void transform() override {
cout << "变成人兽 -- 蝙蝠人形态..." << endl;
}
void ability() override {
cout << "声纳-引剑之万归宗..." << endl;
}
};

//定义工厂类 --- 父类
class AbstractFactory { //抽象类(虚工厂)
public:
virtual AbstractSmile* createSmile() = 0;
virtual ~AbstractFactory() {}
};

//生产山羊的恶魔果实(通过子工厂来继承虚工厂)
class SheepFactory : public AbstractFactory {
public:
AbstractSmile* createSmile() { //父类指针指向子类对象
return new SheepSmile;
}
~SheepFactory() {
cout << "SheppFactory被析构了..." << endl;
}
};

//生产狮子的恶魔果实
class LionFactory : public AbstractFactory {
public:
AbstractSmile* createSmile() {
return new LionSmile;
}
~LionFactory() {
cout << "LionFactory被析构了..." << endl;
}
};

//生产蝙蝠的恶魔果实
class BatFactory : public AbstractFactory {
public:
AbstractSmile* createSmile() {
return new BatSmile;
}
~BatFactory() {
cout << "BatFactory被析构了..." << endl;
}
};

int main() {
//AbstractFactory factory; //AbstractFactory是抽象类了,不能这样实例化一个抽象类
AbstractFactory* factory = new LionFactory; //父类指针指向子类对象
AbstractSmile* obj = factory->createSmile(); //同样也是父类指针指向子类对象,factory执行的函数是子类对象重写的
obj->transform();
obj->ability();
delete obj;
delete factory;
return 0;
}

3.3 抽象工厂模式

抽象工厂模式适用于比较复杂的多变的业务场景,总体上就是给一系列功能相同但是属性会发生变化的组件(如:船体材料、武器系统、动力系统)添加一个抽象类,这样就可以非常方便地进行后续的拓展,再搭配工厂类就可以创建出我们需要的对象了。

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
//船体
class ShipBody {
public:
virtual string getBody() = 0;
virtual ~ShipBody() {}
};
//木头船体
class WoodBody :public ShipBody {
public:
string getBody() override {
return string("使用<木材>制作海贼船的船体...");
}
};
//钢铁船体
class IronBody :public ShipBody {
public:
string getBody() override {
return string("使用<钢铁>制作海贼船的船体...");
}
};
//合成金属船体
class MetalBody :public ShipBody {
public:
string getBody() override {
return string("使用<合成金属>制作海贼船的船体...");
}
};

//引擎
class Engine {
public:
virtual string getEngine() = 0;
virtual ~Engine() {}
};
//手动引擎
class Human :public Engine {
public:
string getEngine() {
return "海贼船的动力方式是<手动>...";
}
};
//内燃机引擎
class Diesel :public Engine {
public:
string getEngine() {
return "海贼船的动力方式是<内燃机>...";
}
};
//手动引擎
class Nuclear :public Engine {
public:
string getEngine() {
return "海贼船的动力方式是<核反应堆>...";
}
};

//武器
class Weapon {
public:
virtual string getWeapon() = 0;
virtual ~Weapon() {}
};
//枪
class Gun : public Weapon {
public:
string getWeapon() {
return string("船上的武器系统是<枪>...");
}
};
//加农炮
class Cannon : public Weapon {
public:
string getWeapon() {
return string("船上的武器系统是<加农跑>...");
}
};
//激光
class Laser : public Weapon {
public:
string getWeapon() {
return string("船上的武器系统是<激光>...");
}
};

//船
class Ship { //船这个类里面又还要三个子类
public:
//通过传进来的对于子类对象,实现父类指针指向子类对象
Ship(ShipBody* body, Engine* engine, Weapon* weapon) : //三个子对象之间这里是组合关系,当析构船对象的时候,一并析构掉这三个子对象
m_body(body), m_engine(engine), m_weapon(weapon) {}
~Ship() { //组合关系,析构掉三个子对象
delete m_body;
delete m_weapon;
delete m_engine;
}
string getProperty() {
string info = m_body->getBody() + m_weapon->getWeapon() + m_engine->getEngine();
return info;
}

private:
ShipBody* m_body; //船体父类对象
Engine* m_engine; //引擎父类对象
Weapon* m_weapon; //武器父类对象
};

//工厂类 --- 抽象
class AbstractFactory {
public:
virtual Ship* createShip() = 0;
virtual ~AbstractFactory() {}
};

//基础型海贼船子工厂 ---> 继承父工厂
class BasicFactory :public AbstractFactory {
public:
Ship* createShip() override {
Ship* ship = new Ship(new WoodBody, new Human, new Gun); //相当于通过传参构造Ship
cout << "<基础型的海贼船> 已经建造完毕!!!" << endl;
return ship;
}
};

//标准型海贼船子工厂 ---> 继承父工厂
class StandardFactory :public AbstractFactory {
public:
Ship* createShip() override {
Ship* ship = new Ship(new IronBody, new Diesel, new Cannon);
cout << "<标准型的海贼船> 已经建造完毕!!!" << endl;
return ship;
}
};

//旗舰型海贼船子工厂 ---> 继承父工厂
class UltimataFactory :public AbstractFactory {
public:
Ship* createShip() override {
Ship* ship = new Ship(new MetalBody, new Nuclear, new Laser);
cout << "<旗舰型的海贼船> 已经建造完毕!!!" << endl;
return ship;
}
};

int main() {
//下单为旗舰型海贼船
AbstractFactory* factory = new UltimataFactory; //父工厂指针指向子工厂对象
Ship* ship = factory->createShip(); //创建对应的船,并返回
cout << ship->getProperty() << endl;
delete ship;
delete factory;
return 0;
}

最后对简单工厂模式工厂模式抽象工厂模式的区别做如下总结:

  • 简单工厂模式不能遵守开放封闭原则,工厂和抽象工厂模式可以
  • 简单工厂模式只有一个工厂类,工厂和抽象工厂有多个工厂类
  • 工厂模式创建的产品对象相对简单,抽象工厂模式创建的产品对象相对复杂
    • 工厂模式创建的对象对应的类不需要提供抽象类(这产品类组件中没有可变因素)
    • 抽象工厂模式创建的对象对应的类有抽象的基类(这个产品类组件中有可变因素)

4. 建造者(生成器)模式

下面程序为创造模式的一个例子。

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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// 定义桑尼号的船
class SunnyShip {
public:
void addParts(string name) {
m_parts.push_back(name);
}
void showParts() {
for (const auto& item : m_parts) {
cout << item << " ";
}
cout << endl;
}
private:
vector<string> m_parts;
};

//定义梅丽号的船
class MerryShip {
public:
void assemble(string name, string parts) {
m_parts.insert(make_pair(parts,name));
}
void showParts() {
for (const auto& item : m_parts) {
cout << item.first<< ":" << item.second;
}
cout << endl;
}
private:
map<string, string> m_parts;
};

//定义生成器类:在这个抽象类中定义了建造海贼船所有零部件的方法,在这个类的子类中需要重写这些虚函数,分别完成桑尼号 和梅利号零件的建造。
class ShipBuilder {
public:
virtual void reset() = 0;
virtual void buildBody() = 0;
virtual void buildWeapon() = 0;
virtual void buildEngine() = 0;
virtual void buildInterior() = 0;
virtual ~ShipBuilder() {}
};

//桑尼号生成器
class SunnyBuilder :public ShipBuilder {
public:
SunnyBuilder() {
reset();
}
void reset()override {
m_sunny = new SunnyShip; //创建一个桑尼号船
}
SunnyShip* getSunnyShip() {
SunnyShip* ship = m_sunny; //当在m_sunny对象里面存储了对应组件后,就可以返回给调用者了
m_sunny = nullptr; //旧内存就不需要维护了(后面还需要创建不同型号的桑尼号)
return ship;
}
void buildBody() override {
m_sunny->addParts("船体是神树亚当");
}
void buildWeapon() override {
m_sunny->addParts("狮吼炮");
}
void buildEngine() override {
m_sunny->addParts("可乐驱动的内燃机");
}
void buildInterior() override {
m_sunny->addParts("非常豪华的内室装修");
}
~SunnyBuilder() {
if (m_sunny) {
delete m_sunny;
}
}
private:
SunnyShip* m_sunny; //定义一个桑尼船的对象
};

//梅丽号生成器
class MerryBuilder :public ShipBuilder {
public:
MerryBuilder() {
reset();
}
void reset() override {
m_merry = new MerryShip;
}
MerryShip* getMerryShip() {
MerryShip* ship = m_merry;
m_merry = nullptr; //旧内存就不需要维护了
return ship;
}
void buildBody() override {
m_merry->assemble("船体是优质木材","船体");
}
void buildWeapon() override {
m_merry->assemble("普通的四门大炮","武器系统");
}
void buildEngine() override {
m_merry->assemble("烧煤的蒸汽机","动力系统");
}
void buildInterior() override {
m_merry->assemble("非常豪华的内室装修","内室");
}
~MerryBuilder() {
if (m_merry) {
delete m_merry;
}
}
private:
MerryShip* m_merry; //定义一个桑尼船的对象
};

//定义管理者
class Director {
public:
void setBuilder(ShipBuilder* builder) { //多态实现,参数传进来的可能是桑尼号也可能是梅丽号
m_builder = builder;
}
//简约型
void buildSimpleShip() {
m_builder->buildBody();
m_builder->buildEngine();
}
//标准型
void buildStandardShip() {
buildSimpleShip();
m_builder->buildWeapon(); //在简约型的基础上多了一个武器
}
//豪华型
void buildRegalShip() {
buildStandardShip();
m_builder->buildInterior(); //在标准型基础上多了一个内室装饰
}
private:
ShipBuilder* m_builder = nullptr;
};

//创建桑尼号
void buildSunnyShip() {
Director* director = new Director; //创建出一个管理类对象
SunnyBuilder* builder = new SunnyBuilder; //创建一个桑尼号船对象

//简约型
director->setBuilder(builder); //多态实现,父类指针指向子类对象
director->buildSimpleShip(); //创建一个简约型的桑尼号
SunnyShip* ship = builder->getSunnyShip(); //取出它的一个ship,里面容器存了对应的字符串
ship->showParts(); //打印简约型桑尼号组件
delete ship;

//标准型
builder->reset(); //重新创建一个ship的子类(存对应桑尼号组件的)
director->buildStandardShip();
ship = builder->getSunnyShip();
ship->showParts();
delete ship;

//豪华型
builder->reset();
director->buildRegalShip();
ship = builder->getSunnyShip();
ship->showParts();
delete ship;
delete builder;
delete director;
}

//建造梅丽号
void buildMerryShip() {
Director* director = new Director;
MerryBuilder* builder = new MerryBuilder;

//简约型
director->setBuilder(builder);
director->buildSimpleShip();
MerryShip* ship = builder->getMerryShip();
ship->showParts();
delete ship;

//标准型
builder->reset();
director->buildStandardShip();
ship = builder->getMerryShip();
ship->showParts();
delete ship;

//豪华型
builder->reset();
director->buildRegalShip();
ship = builder->getMerryShip();
ship->showParts();
delete ship;
delete builder;
delete director;
}

int main() {
buildMerryShip();
cout << "=============================" << endl;
buildSunnyShip();
}

5. 原型模式

通过父类指针把对应的子类对象拷贝出来,就是让子类重写了父类提供的克隆函数,然后在每个子类的克隆函数里面调用了子类对应的拷贝构造函数,再通过父类指针指向某一个子类对象,这样就通过指针能够调用某个子类里面的克隆函数了,执行的就是对应子类里面的拷贝动作,这样就能够得到对应的子类实例对象(不是原来那个了)。

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
//父类(抽象类)
class GermaSoldier {
public:
virtual GermaSoldier* clone() = 0; //纯虚函数
virtual string whoAmI() = 0;
virtual ~GermaSoldier() {} //虚析构(同时会析构子类对象)
};

//子类
class Soldier66 :public GermaSoldier {
public:
GermaSoldier* clone() override {
return new Soldier66(*this); //谁调用clone,this就是谁
}
string whoAmI() override {
return "我是soldier66的士兵!!!";
}
};

class Soldier67 :public GermaSoldier {
public:
GermaSoldier* clone() override {
return new Soldier67(*this);
}
string whoAmI() override {
return "我是soldier67的士兵!!!";
}
};

int main() {
GermaSoldier* obj = new Soldier66;
GermaSoldier* soldier = obj->clone(); //obj->clone克隆出来的是Soldier66的对象
cout << soldier->whoAmI();
delete soldier;
delete obj;

obj = new Soldier67;
soldier = obj->clone(); //obj->clone克隆出来的是Soldier67的对象
cout << soldier->whoAmI();
delete soldier;
delete obj;
}

6.适配器模式

适配器就是将一个类的接口转换成用户希望的另一个接口,使不兼容的对象能够相互配合并一起工作,这种模式就叫适配器模式。

STL标准模板库有六大组件,其中之一的就是适配器。

  • 六大组件分别是:容器、算法、迭代器、仿函数、适配器、空间适配器。
  • 适配器又可以分为:容器适配器、函数适配器、迭代器适配器

1.适配器类和熊猫类是关联关系:

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
//外国人
class Foreigner {
public:
virtual string confession() = 0; //纯虚函数,让子类实现,美国人和法国人说的话
void setResult(string res) { //收到熊猫的回复
cout << "Panda say: " << res << endl;
}
virtual ~Foreigner() {}
};

//美国人
class Ammerican : public Foreigner {
public:
string confession() override {
return "我有罪,呼呼呼!!!";
}
};
//法国人
class French : public Foreigner {
public:
string confession() override {
return "我不是人,哎哎哎!!!";
}
};

//熊猫
class Panda {
public:
void recvMessage(string msg) { //接收的数据
cout << msg << endl;
}
string sendMessage() { //发送的数据
return string("强盗、凶手,罪人是不可能被宽恕和原谅的!! ");
}
};

//适配器父类
class AbstractChopper {
public:
//传入的参数是美国人对象或法国人对象
AbstractChopper(Foreigner* foreigner) : m_foreigner(foreigner) {}
virtual void translateToPanda() = 0; //把人类的语言转换为熊猫的语言
virtual void translateToHuman() = 0; //把熊猫的语言转换为人类的语言
protected:
Panda m_panda; //熊猫对象
Foreigner* m_foreigner; //外国人对象(保存传进来的外国人的实例)
};

//适配器子类(熊猫语言与英语之间的转换)
class EnglishChopper : public AbstractChopper {
public:
using AbstractChopper::AbstractChopper; //在子类里面就继承了所有在父类中定义的构造函数
//把人类的语言转换为熊猫的语言
void translateToPanda() {
string msg = m_foreigner->confession(); //取出美国人说的话
//解析熊猫的语言,并将数据传递给熊猫
m_panda.recvMessage("美国人说: " + msg); //熊猫接收到美国人的话
}
//把熊猫的语言转换为人类的语言
void translateToHuman() {
string msg = m_panda.sendMessage(); //取出熊猫回复的话
//将熊猫语言转换为英语,再传递给外国人
m_foreigner->setResult("美国佬: " + msg); //外国人接收到熊猫的话
}
};

//适配器子类(熊猫语言与法语之间的转换)
class FrechChopper : public AbstractChopper {
public:
using AbstractChopper::AbstractChopper; //在子类里面就继承了所有在父类中定义的构造函数
//把人类的语言转换为熊猫的语言
void translateToPanda() {
string msg = m_foreigner->confession();
//解析熊猫的语言,并将数据传递给熊猫
m_panda.recvMessage("法国人说: " + msg);
}
//把熊猫的语言转换为人类的语言
void translateToHuman() {
string msg = m_panda.sendMessage();
//将熊猫语言转换为英语,再传递给外国人
m_foreigner->setResult("法国佬: " + msg);
}
};

int main() {
Foreigner* foreigner = new Ammerican; //定义一个外国人的对象(多态实现,指向美国人对象)
AbstractChopper* adapter = new EnglishChopper(foreigner); //转换器对象(对应的是英语转换器)
adapter->translateToPanda(); //英语转换为熊猫语言
adapter->translateToHuman(); //熊猫语言转换为英语
delete foreigner;
delete adapter;
cout << "=====================================" << endl;
foreigner = new French; //定义一个外国人的对象(多态实现,指向美国人对象)
adapter = new FrechChopper(foreigner); //转换器对象(对应的是英语转换器)
adapter->translateToPanda(); //英语转换为熊猫语言
adapter->translateToHuman(); //熊猫语言转换为英语
delete foreigner;
delete adapter;
}

2.适配器类和熊猫类是继承关系:因为熊猫类是没有子类的,所以可以让适配器父类来继承熊猫类,这样在适配器子类中使用熊猫类的recvMessage()函数和sendMessage()函数就可以直接使用,而不需要通过m_panda.来引用。当然,当外国人类也没有子类时,适配器父类就可以继承熊猫类和适配器类(多个类)来实现相应的功能了。

7. 桥接模式

桥接模式的原则就是将抽象部分和它的实现部分分离,使它们可以独立的变化。

比如说在下面程序中,实现桥接模式的方案:

  • 海贼团之间是继承关系,但是此时的海贼团也只是一个抽象,因为组成海贼团的人已经被抽离了,船员已经和所属的海贼团没有了继承关系。
  • 关于海贼世界的船员在船上对应不同的职责担任不同的职务,他们是一个团队,所以可以给船员抽象出一个团队类,用于管理船上的成员。
  • 抽象的海贼团只有一个空壳子,所以要赋予其灵魂也就是给它添加船员,此时的海贼团和船员团队可以通过聚合的方式组合成为一个整体。
  • 这种解决方案不仅适用于管理海贼团,用于管理海军的各个舰队也是没有问题的。

测试程序:对海贼世界中的 海贼团 和 海军 通过桥接模式进行管理

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
//成员对应的类
struct Person {
//构造函数
Person(string name, string job, string ability, string reward, string beizhu) {
this->name = name;
this->job = job;
this->ability = ability;
this->reward = reward;
this->beizhu = beizhu;
}
~Person() {
cout << name << "被析构了..." << endl;
}
string name;
string job;
string ability;
string reward;
string beizhu;
};

//定义实现部分 - 团队
class AbstractTeam {
public:
AbstractTeam(string name) : m_name(name) {} //初始化团队的名字
string getTeamName() { //获取团队的名字
return m_name;
}
void addMember(Person* p) {
m_teamMap.insert(make_pair(p->name, p)); //插入成员
}
void show() {
cout << m_name << ": " << endl;
for (const auto& item : m_teamMap) {
cout << "[name: " << item.second->name
<< ", job: " << item.second->job
<< ", abilite: " << item.second->ability
<< ", reward: " << item.second->reward
<< ", beizhu: " << item.second->beizhu
<< "] " << endl;
}
}
virtual ~AbstractTeam() {
for (const auto& item : m_teamMap) {
delete item.second;
}
}
virtual void executeTask() = 0; //纯虚函数的任务函数,让子类来写
protected:
string m_name;
map<string, Person*> m_teamMap;
};

//草帽子团队
class CaoMaoTeam :public AbstractTeam {
public:
using AbstractTeam::AbstractTeam; //继承父类的构造函数(获取团队名)
void executeTask() override {
cout << "在海上冒险,找到 ONE PIECE 成为海贼王!!! " << endl;
}
};
//海军子团队
class SmokerTeam :public AbstractTeam {
public:
using AbstractTeam::AbstractTeam; //继承父类的构造函数(获取团队名)
void executeTask() override {
cout << "为了正义,先将草帽一网打尽!!! " << endl;
}
};

//定义抽象部分 - 船
class AbstractShip {
public:
AbstractShip(AbstractTeam* team) :m_team(team) {} //初始化一个团队
void show() {
m_team->show(); //展示团队成员
m_team->executeTask(); //打印团队的目标
}
virtual string getName() = 0; //船的名字
virtual void feature() = 0; //船的属性

protected:
AbstractTeam* m_team;
};

//梅丽号子船类
class Merry :public AbstractShip {
public:
using AbstractShip::AbstractShip; //继承父类的构造函数
string getName() override {
return "前进 - 梅利号";
}
void feature() override {
cout << getName() << "-- 船首为羊头,化身船精灵在司法岛舍己救下了草帽一伙!!! " << endl;
}
};
//海军船子船类
class HaiJunShip :public AbstractShip {
public:
using AbstractShip::AbstractShip; //继承父类的构造函数
string getName() override {
return "无敌海军号";
}
void feature() override {
cout << getName() << "-- 船底由海楼石建造,可以穿过无风带的巨大炮舰!!! " << endl;
}
};

int main() {
//CaoMaoTeam* team = new CaoMaoTeam("草帽海贼团"); //不通过多态实现也可以
CaoMaoTeam* team = new CaoMaoTeam("草帽海贼团"); //创建一个团队
Person* luffy = new Person("路飞", "船长", "橡胶果实能力者", "30亿贝利", "爱吃肉");
Person* zoro = new Person("索隆", "剑士", "三刀流", "12亿贝利", "路痴");
Person* sanji = new Person("山治", "厨师", "火焰腿", "10亿贝利", "好色");
Person* nami = new Person("娜美", "航海士", "天候棒", "3亿贝利", "喜欢钱");
team->addMember(luffy); //因为子团队继承了父团队,所以可以使用父团队的函数
team->addMember(zoro);
team->addMember(sanji);
team->addMember(nami);
//Merry* ship = new Merry(team); //不通过多态实现也可以
AbstractShip* ship = new Merry(team); //创建梅丽船,传入的参数是草帽团队
ship->show(); //打印团队成员和目标(该函数里面就是通过传入的草帽团队调用了对应的函数)
ship->feature(); //打印船的属性
delete team;
delete ship;
}

8. 组合模式

能将多个对象组成一个树状结构,用以描述部分—整体的层次关系,使得用户对单个对象和组合对象的使用具有一致性,这样的结构性设计模式叫做组合模式

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
//定义节点的抽象类
class AbstractTeam {
public:
AbstractTeam(string name) : m_name(name) {}
string getName() { //获取团队名字
return m_name;
}
void setParent(AbstractTeam* team) { //设置父对象
m_parent = team;
}
AbstractTeam* getParent() { //获取父对象
return m_parent;
}
//虚函数
virtual bool hasChild() { //是否有子节点,默认返回false(叶子节点就可以不用重写该函数了,管理者节点需要重写)
return false;
}
//这两个函数不能定义成纯虚函数:因为如果这个抽象类的子类是一个叶子节点,叶子节点是用不到这两个函数的,所以就不需要重写这两个
//虚函数。如果定义成纯虚函数,子类就必须重写,不然也是抽象类(不能被实例化),所以不定义成虚函数,子类就算继承了,该函数也是什么都不执行
virtual void addChild(AbstractTeam* node) {} //添加节点
virtual void removeChild(AbstractTeam* node) {} //删除节点

//纯虚函数(子类必须重写的)
virtual void fight() = 0;
virtual void display() = 0;
virtual ~AbstractTeam() {} //虚析构函数
protected:
string m_name; //记录团队的名字
AbstractTeam* m_parent = nullptr; //记录父对象
};

//叶子节点类
class LeafTeam :public AbstractTeam {
public:
using AbstractTeam::AbstractTeam; //继承父类定义的所有构造函数
void fight() {
cout << m_parent->getName() + m_name + "与黑胡子的船员进行近距离肉搏战... " << endl;
}
void display() {
cout << "我是" << m_parent->getName() << "下属的" << m_name << endl;
}
~LeafTeam() {
cout << "我是" << m_parent->getName() << "下属的" << m_name << ",战斗已经结束,拜拜... " << endl;
}
};

//管理者节点类
class ManagerTeam :public AbstractTeam {
public:
using AbstractTeam::AbstractTeam; //继承父类定义的所有构造函数
void fight() {
cout << m_name + "与黑胡子的恶魔果实能力者战斗... " << endl;
}
bool hasChild() { //是否有子节点
return true;
}
void addChild(AbstractTeam* node) { //添加下属团队
node->setParent(this); //上级节点就为这个类对象
m_children.push_back(node); //加入该团队的下属
}
void removeChild(AbstractTeam* node) { //删除下属团队
node->setParent(nullptr); //给它的上级节点指为空
m_children.remove(node); //移除
}
void display() { //如果是管理者节点,则就打印他的下属团队
string info;
for (const auto& item : m_children) { //遍历他的下属团队
if (item == m_children.back()) {
info += item->getName(); //如果是最后一个,就直接追加在后面即可
}
else {
info += item->getName() + ", "; //如果不是最后一个,就添加逗号,继续追加
}
}
cout << m_name << "的船队是[" << info << "]" << endl;
}
list<AbstractTeam*> getChildren() { //取出他的下属
return m_children;
}
~ManagerTeam() {
cout << "我是[ " << m_name << " ] 战斗结束,拜拜..." << endl;
}
private:
list<AbstractTeam*> m_children; //来记录它的孩子节点(记录它的下属)
};

void gameover(AbstractTeam* root) { //递归消除节点
if (root == nullptr) {
return;
}
if (root && root->hasChild()) { //不为空,且有下属
ManagerTeam* team = dynamic_cast<ManagerTeam*>(root);
list<AbstractTeam*> children = team->getChildren(); //取出该节点的子节点(下属)
for (const auto& item : children) { //
gameover(item);
}
}
delete root;
}

void fighting() {
//根节点
ManagerTeam* root = new ManagerTeam("草帽海贼团");
vector<string> nameList = { "俊美海贼团","巴托俱乐部","八宝水军","艾迪欧海贼团","咚塔塔海贼团",
"巨兵海贼团","约塔玛利亚大船团" };
for (int i = 0; i < nameList.size(); i++) {
ManagerTeam* child = new ManagerTeam(nameList.at(i));
root->addChild(child);
if (i == nameList.size() - 1) {
for (int j = 0; j < 9; j++) {
LeafTeam* leaf = new LeafTeam("第" + to_string(j + 1) + "番队");
child->addChild(leaf);
leaf->fight();
leaf->display();
}
}
}
}
int main() {
fighting();
}