C++设计模式

《大话设计模式》一书中提到 24 种设计模式,这 24 种设计模式没必要面面俱到,但一定要深入了解其中的几种,以下列举常见的3种设计模式,单例模式,工厂模式,观察者模式。在这之前,先让我们来熟悉一下6大设计原则。

设计原则

单一职责原则:

就一个类而言,应该仅有一个引起它变化的原因。

开放封闭原则:

软件实体可以扩展,但是不可修改。即面对需求,对程序的改动可以通过增加代码来完成,但是不能改动现有的代码。

里氏代换原则:

一个软件实体如果使用的是一个基类,那么一定适用于其派生类。即在软件中,把基类替换成派生类,程序的行为没有变化。

依赖倒转原则:

抽象不应该依赖细节,细节应该依赖抽象。即针对接口编程,不要对实现编程。

迪米特原则:

如果两个类不直接通信,那么这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的某个方法的话,可以通过第三个类转发这个调用。

接口隔离原则:

每个接口中不存在派生类用不到却必须实现的方法,如果不然,就要将接口拆分,使用多个隔离的接口。

设计模式

单例模式

保证类的实例化对象仅有一个,并且提供一个访问他的全局访问点。

应用场景

表示文件系统的类,一个操作系统一定是只有一个文件系统,因此文件系统的类的实例有且仅有一个。
打印机打印程序的实例,一台计算机可以连接好几台打印机,但是计算机上的打印程序只有一个,就可以通过单例模式来避免两个打印作业同时输出到打印机。

即广泛用于文件io这种不能同时写的情况。

实现方式:

单例模式可以通过全局或者静态变量的形式实现,这样比较简单,但是这样会影响封装性,难以保证别的代码不会对全局变量造成影响。

默认的构造函数、拷贝构造函数、赋值构造函数声明为私有的,这样禁止在类的外部创建该对象;
全局访问点也要定义成 静态类型的成员函数,没有参数,返回该类的指针类型。因为使用实例化对象的时候是通过类直接调用该函数,并不是先创建一个该类的对象,通过对象调用。
不安全的实现方式:
原因:考虑当两个线程同时调用 getInstance 方法,并且同时检测到 instance 是 NULL,两个线程会同时实例化对象,不符合单例模式的要求。

懒汉模式

直到第一次用到类的实例时才去实例化。以下是懒汉的实现。注意,懒汉并非是线程安全的,线程安全需要加锁才能保证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Singleton {
public:
static Singleton* GetInstance() {
std::lock_guard<std::mutex> lock(_mutex);
if(instance == nullptr){
instance = new Singleton();
}
return instance;
}
private:
Singleton(){} // 禁止构造
Singleton(const Singleton& tmp){}
static Singleton* instance;
static std::mutex _mutex;
};
Singleton* Singleton::instance = nullptr;

当多线程访问次对象时由于互斥访问可能会造成阻塞。又或者,我们之间返回instance中的静态实例对象。

1
2
3
4
5
6
7
8
9
10
class Singleton {
public:
static Singleton* GetInstance() {
static Singleton instance;
return &instance;
}
private:
Singleton(){}
Singleton(const Singleton& tmp){}
};

饿汉模式

饿汉模式是指一开始就将资源初始化,饿汉模式本身就是线程安全的不用加锁。

1
2
3
4
5
6
7
8
9
10
11
class Singleton {
public:
static Singleton* GetInstance() {
return instance;
}
private:
Singleton(){} // 禁止构造
Singleton(const Singleton& tmp){}
static Singleton* instance;
};
Singleton* Singleton::instance = new Singleton();

工厂模式

简单工厂模式:

主要用于创建对象。用一个工厂来根据输入的条件产生不同的类,然后根据不同类的虚函数得到不同的结果。

应用场景:适用于针对不同情况创建不同类时,只需传入工厂类的参数即可,无需了解具体实现方法。

image-20210728081253359

由派生类具体操作类继承基类抽象操作类,具体操作类由工厂构造。

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

// Here is the product class
class Operation
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};

class Add_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};

class Sub_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};

class Mul_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};

class Div_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};

// Here is the Factory class
class Factory
{
public:
static Operation *CreateProduct(char op)
{
switch (op)
{
case '+':
return new Add_Operation();

case '-':
return new Sub_Operation();

case '*':
return new Mul_Operation();

case '/':
return new Div_Operation();

default:
return new Add_Operation();
}
}
};

int main()
{
int a, b;
cin >> a >> b;
Operation *p = Factory::CreateProduct('+');
p->var1 = a;
p->var2 = b;
cout << p->GetResult() << endl;

p = Factory::CreateProduct('*');
p->var1 = a;
p->var2 = b;
cout << p->GetResult() << endl;

return 0;
}

工厂方法模式

修正了简单工厂模式中不遵守开放封闭原则。把选择判断移到了客户端去实现,如果想添加新功能就不用修改原来的类,直接修改客户端即可。

应用场景:

一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
一个类通过其派生类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其派生类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,派生类对象将覆盖父类对象,从而使得系统更容易扩展。
将创建对象的任务委托给多个工厂派生类中的某一个,客户端在使用时可以无须关心是哪一个工厂派生类创建产品派生类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

image-20210728081925081

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
class Operation
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};

class Add_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};

class Sub_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};

class Mul_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};

class Div_Operation : public Operation
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};

class Factory
{
public:
virtual Operation *CreateProduct() = 0;
};

class Add_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Add_Operation();
}
};

class Sub_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Sub_Operation();
}
};

class Mul_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Mul_Operation();
}
};

class Div_Factory : public Factory
{
public:
Operation *CreateProduct()
{
return new Div_Operation();
}
};

int main()
{
int a, b;
cin >> a >> b;
Add_Factory *p_fac = new Add_Factory();
Operation *p_pro = p_fac->CreateProduct();
p_pro->var1 = a;
p_pro->var2 = b;
cout << p_pro->GetResult() << endl;

Mul_Factory *p_fac1 = new Mul_Factory();
Operation *p_pro1 = p_fac1->CreateProduct();
p_pro1->var1 = a;
p_pro1->var2 = b;
cout << p_pro1->GetResult() << endl;

return 0;
}

抽象工厂模式

定义了一个创建一系列相关或相互依赖的接口,而无需指定他们的具体类。

应用场景:

一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
系统中有多于一个的产品族,而每次只使用其中某一产品族。
属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的
产品等级结构。

image-20210728082701125

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

// Here is the product class
class Operation_Pos
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};

class Add_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 + var2;
}
};

class Sub_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 - var2;
}
};

class Mul_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 * var2;
}
};

class Div_Operation_Pos : public Operation_Pos
{
public:
virtual double GetResult()
{
return var1 / var2;
}
};
/*********************************************************************************/
class Operation_Neg
{
public:
int var1, var2;
virtual double GetResult()
{
double res = 0;
return res;
}
};

class Add_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 + var2);
}
};

class Sub_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 - var2);
}
};

class Mul_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 * var2);
}
};

class Div_Operation_Neg : public Operation_Neg
{
public:
virtual double GetResult()
{
return -(var1 / var2);
}
};
/*****************************************************************************************************/

// Here is the Factory class
class Factory
{
public:
virtual Operation_Pos *CreateProduct_Pos() = 0;
virtual Operation_Neg *CreateProduct_Neg() = 0;
};

class Add_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Add_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Add_Operation_Neg();
}
};

class Sub_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Sub_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Sub_Operation_Neg();
}
};

class Mul_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Mul_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Mul_Operation_Neg();
}
};

class Div_Factory : public Factory
{
public:
Operation_Pos *CreateProduct_Pos()
{
return new Div_Operation_Pos();
}
Operation_Neg *CreateProduct_Neg()
{
return new Div_Operation_Neg();
}
};

int main()
{
int a, b;
cin >> a >> b;
Add_Factory *p_fac = new Add_Factory();
Operation_Pos *p_pro = p_fac->CreateProduct_Pos();
p_pro->var1 = a;
p_pro->var2 = b;
cout << p_pro->GetResult() << endl;

Add_Factory *p_fac1 = new Add_Factory();
Operation_Neg *p_pro1 = p_fac1->CreateProduct_Neg();
p_pro1->var1 = a;
p_pro1->var2 = b;
cout << p_pro1->GetResult() << endl;

return 0;
}

观察者模式

观察者模式:定义一种一(被观察类)对多(观察类)的关系,让多个观察对象同时监听一个被观察对象,被观察对象状态发生变化时,会通知所有的观察对象,使他们能够更新自己的状态。

观察者模式中存在两种角色:

观察者:内部包含被观察者对象,当被观察者对象的状态发生变化时,更新自己的状态。(接收通知更新状态)
被观察者:内部包含了所有观察者对象,当状态发生变化时通知所有的观察者更新自己的状态。(发送通知)
应用场景:

当一个对象的改变需要同时改变其他对象,且不知道具体有多少对象有待改变时,应该考虑使用观察者模式;
一个抽象模型有两个方面,其中一方面依赖于另一方面,这时可以用观察者模式将这两者封装在独立的对象中使它们各自独立地改变和复用。

image-20210728085249732

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

class Subject;
//观察者 基类 (内部实例化了被观察者的对象sub)
class Observer
{
protected:
string name;
Subject *sub;

public:
Observer(string name, Subject *sub)
{
this->name = name;
this->sub = sub;
}
virtual void update() = 0;
};

class StockObserver : public Observer
{
public:
StockObserver(string name, Subject *sub) : Observer(name, sub)
{
}
void update();
};

class NBAObserver : public Observer
{
public:
NBAObserver(string name, Subject *sub) : Observer(name, sub)
{
}
void update();
};
//被观察者 基类 (内部存放了所有的观察者对象,以便状态发生变化时,给观察者发通知)
class Subject
{
protected:
list<Observer *> observers;

public:
string action; //被观察者对象的状态
virtual void attach(Observer *) = 0;
virtual void detach(Observer *) = 0;
virtual void notify() = 0;
};

class Secretary : public Subject
{
void attach(Observer *observer)
{
observers.push_back(observer);
}
void detach(Observer *observer)
{
list<Observer *>::iterator iter = observers.begin();
while (iter != observers.end())
{
if ((*iter) == observer)
{
observers.erase(iter);
return;
}
++iter;
}
}
void notify()
{
list<Observer *>::iterator iter = observers.begin();
while (iter != observers.end())
{
(*iter)->update();
++iter;
}
}
};

void StockObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
}
}

void NBAObserver::update()
{
cout << name << " 收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!")
{
cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
}
}

int main()
{
Subject *dwq = new Secretary();
Observer *xs = new NBAObserver("xiaoshuai", dwq);
Observer *zy = new NBAObserver("zouyue", dwq);
Observer *lm = new StockObserver("limin", dwq);

dwq->attach(xs);
dwq->attach(zy);
dwq->attach(lm);

dwq->action = "去吃饭了!";
dwq->notify();
cout << endl;
dwq->action = "梁所长来了!";
dwq->notify();
return 0;
}

参考资料

[1]https://leetcode-cn.com/leetbook/read/cpp-interview-highlights/o5v4w6/