Design Pattern

  • 36个设计模式

设计模式

设计模式简介

  • 松耦合设计
  • 面向对象设计原则
  • 重构技法
  • GOF核心设计

《设计模式-可复用 面向对象 软件的基础》

mark

mark

软件设计复杂的根本原因:

  • 客户需求变化
  • 技术平台变化
  • 开发团队变化
  • 市场环境变化

解决复杂性:

  • 分而治之
    • shape: 2 个shape
    • MainForm: shape1 shape2
  • 抽象
    • shape: 2个shape 继承父类shape ,实现各自paint

尽可能一个class一个文件。

软件设计的目标:

复用

面向对象设计原则

原则大于模式

mark

  • 依赖倒置原则DIP

    • 从而隔离变化
    • 高层模块(稳定)不应该依赖于底层模块(变化),二者都应该依赖与抽象(稳定)。
    • 抽象(稳定) 不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)
  • 开放封闭原则OCP

    • 对扩展开放,对更改封闭
    • 类模块应该是可以扩展的,但是不可以修改
  • 单一职责原则SRP

    • 一个类应该仅有一个引起它变化的原因
    • 变化的方向隐含着类的责任
  • Liskov 替换原则LSP

    • 子类必须能够替换他们的基类IS-A
    • 继承表达类型抽象
  • 接口隔离原则ISP

    • 不应该强波客户程序依赖它们不用的方法
    • 接口应该小而完备
  • 优先使用对象组合,而不是类继承

    • 类继承通常为白箱复用,对象组合通常为黑箱复用
    • 继承在某种程度上破坏了封装性,子类父类耦合度高
    • 而对象组合只要求被组合的对象具有良好定义的接口,耦合度低
  • 封装变化点

    • 使用封装来创建对象之间的分界层,让设计者可以在分界一层进行修改,而不会对另一侧产生不良影响,实现层次间的松耦合
  • 针对接口编程,而不是针对实现编程

    • 不将变量类型声明为某个特定的具体类,而是声明为某个接口
    • 客户程序无需知道对象的具体类型,只需要知道对象所具有的接口
    • 减少系统中各部分的依赖关系,从而实现高内聚,松耦合的设计方案
    • 接口标准化
  • 将设计原则提升为设计经验

    • 设计习语
      • effective c++ // more effective c++ // exceptional c++
    • 设计模式
    • 架构模式

模板方法

GOF-23 模式分类

  • 从目的来看:
    • 创建型(Creational)模式:将对象的部分创建工作延迟到子
      类或者其他对象,从而应对需求变化为对象创建时具体类型实
      现引来的冲击。
    • 结构型(Structural)模式:通过类继承或者对象组合获得更灵
      活的结构,从而应对需求变化为对象的结构带来的冲击。
    • 行为型(Behavioral)模式:通过类继承或者对象组合来划分
      类与对象间的职责,从而应对需求变化为多个交互的对象带来
      的冲击。
  • 从范围来看:
    • 类模式处理类与子类的静态关系。
    • 对象模式处理对象间的动态关系

  • 在变化点应用模式
  • 重构到模式,一步一步修改,最后到模式

重构关键技法:

  • 静态->动态
  • 早绑定->晚绑定
  • 继承->组合
  • 编译时依赖->运行时依赖
  • 紧耦合->松耦合

组建协作模式:

  • 现代软件专业分工之后的第一个结果是“框架应用程序的划
    ”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之
    间的松耦合,是二者之间协作时常用的模式
  • 典型模式
    • template method
    • strategy
    • Ovserver/event

template method 模式

  • 动机

    • 任务,有稳定的整体操作结构,各个子步骤有很多改变的需求,由于固有的原因
      (比如框架与应用之间的关系)而无法和任务的整体结构同时实现
    • 稳定操作结构的前提下,灵活应对各个子步骤的变化,或者晚期实现需求
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 Library{

public:
void Step1(){
//...
}

void Step3(){
//...
}

void Step5(){
//...
}
};

//应用程序开发人员
class Application{
public:
bool Step2(){
//...
}
void Step4(){
//...
}
};
int main()
{
Library lib();
Application app();
lib.Step1();

if (app.Step2()){
lib.Step3();
}

for (int i = 0; i < 4; i++){
app.Step4();
}
lib.Step5();
}

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
//一个基类的析构函数是虚的
//程序库开发人员
class Library{
public:
//稳定 template method
void Run(){
Step1();
if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
}
for (int i = 0; i < 4; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
}
Step5();
}
virtual ~Library(){ }
protected:
void Step1() { //稳定
//.....
}
void Step3() {//稳定
//.....
}
void Step5() { //稳定
//.....
}
virtual bool Step2() = 0;//变化
virtual void Step4() =0; //变化
};

//*******Application***************////
//应用程序开发人员
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
}
virtual void Step4() {
//... 子类重写实现
}
};
int main()
{
Library* pLib=new Application();
lib->Run();
delete pLib;
}
}

  • 早绑定,晚开发的Application 绑定早开发的Libary

  • 晚绑定,早开发的Libary绑定晚开发的Application

模式定义:

  • 一个操作中的算法的骨架(稳定),将一些步骤延迟(变化)到子类中,template method 使得子类可以不改变(复用)一个算法的结构即可重定义(overried)该算法的某些特定步骤
  • 定义一个虚函数,子类重写,支持子类变化
  • 稳定run中有变化 step2,step3。
  • 当run不稳定时,不能用template method
  • 设计模式前提,有一个稳定点、
  • libary 角度来看

区分类图中的稳定和变化

总结:

  • template method 基础,用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
  • 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你 (libary 角度来看)”的反向控制结构时template method的典型应用
  • 在具体实现方面,被template method 调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法

策略模式

mark

  • 加一个时间轴看问题,考虑未来变化
  • 违反开放封闭原则,对扩展开发,对更改封闭,类模块应该是可以扩展的,但是不可以修改
  • 粘贴源代码,不叫复用
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
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
FR_Tax //更改
};

class SalesOrder{
TaxBase tax;
public:
double CalculateTax(){
//...
if (tax == CN_Tax){
//CN***********
}
else if (tax == US_Tax){
//US***********
}
else if (tax == DE_Tax){
//DE***********
}
else if (tax == FR_Tax){ //更改
//...
}
//....
}
};
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
// 一个class 一个文件
class TaxStrategy{
public:
virtual double Calculate(const Context& context)=0;
virtual ~TaxStrategy(){}
};

class CNTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};

class USTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};

class DETax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//***********
}
};
//扩展
//********************************************************///////
class FRTax : public TaxStrategy{
public:
virtual double Calculate(const Context& context){
//.........
}
};
class SalesOrder{
private:
TaxStrategy* strategy;///一个指针,不能对象,多态性,指针可以指向不同的子类//引用也支持多态,不常用
public:
SalesOrder(StrategyFactory* strategyFactory){
this->strategy = strategyFactory->NewStrategy();
}
~SalesOrder(){
delete this->strategy;
}

public double CalculateTax(){
//...
Context context();
double val =
strategy->Calculate(context); //多态调用
//...
}
}

模式定义:

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法(DETax,CNTax)可独立于使用它的客户程序(SalesOrder)(稳定)而变化(扩展,子类化)。

mark

总结:

  • Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便的根据需要在各个算法之间切换
  • strtegy提供了用条件判断语句以外的另一种选择,消除条件判断语句就是在解耦合。含有许多条件判断语句的代码通常都需要strategy模式,除if_else绝对不变。
  • 如果strategy对象没有实例变量,那么各个上下文可以共享一个strategy对象,节省对象开销

Observer观察者模式

动机:

  • 为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化
  • 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合

依赖倒置原则:

  • 高层模块(稳定)不应该依赖于底层模块(变化),二者都应该依赖与抽象(稳定)。
  • 抽象(稳定) 不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)
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
class FileSplitter
{
string m_filePath;
int m_fileNumber;
ProgressBar* m_progressBar;/// add 抽象依赖于实现细节
public:
FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) :
m_filePath(filePath),
m_fileNumber(fileNumber),
m_progressBar(progressBar)
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;//add update bar
m_progressBar->setValue(progressValue);
}
}
};
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
FileSplitter splitter(filePath, number, progressBar);
splitter.split();
}
};

多继承:一个是主继承类,一个是接口

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
class Iprogess{
public:
virtual void DoProgess(float value)=0;
virtual ~Iprogess(){}
};

class FileSplitter
{
string m_filePath;
int m_fileNumber;
Iprogess* iprogress;///////////////
public:
FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) :
m_filePath(filePath),
m_fileNumber(fileNumber),
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;//add update bar
onProgess(progressValue);

}
}
virtual void onProgess(float progressValue)/////
{
iprogress->Doprogess(progressValue);//////
}

};

class MainForm : public Form,public Iprogess
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
FileSplitter splitter(filePath, number);//////
splitter.split();
}
virtual void Doprogess(float value)//////
{
progressBar->setvalue(value);////////
}

};
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
class IProgress{
public:
virtual void DoProgress(float value)=0;
virtual ~IProgress(){}
};
class FileSplitter
{
string m_filePath;
int m_fileNumber;
List<IProgress*> m_iprogressList; // 抽象通知机制,支持多个观察者
public:
FileSplitter(const string& filePath, int fileNumber) :
m_filePath(filePath),
m_fileNumber(fileNumber){
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue);//发送通知
}
}
void addIProgress(IProgress* iprogress){
m_iprogressList.push_back(iprogress);
}
void removeIProgress(IProgress* iprogress){
m_iprogressList.remove(iprogress);
protected:
virtual void onProgress(float value){
List<IProgress*>::iterator itor=m_iprogressList.begin();
while (itor != m_iprogressList.end() )
(*itor)->DoProgress(value); //更新进度条
itor++;
}
}
};

class MainForm : public Form, public IProgress
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){

string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());

ConsoleNotifier cn;

FileSplitter splitter(filePath, number);

splitter.addIProgress(this); //订阅通知
splitter.addIProgress(&cn); //订阅通知
splitter.split();
splitter.removeIProgress(this);
}
virtual void DoProgress(float value){
progressBar->setValue(value);
}
};


class ConsoleNotifier : public IProgress {
public:
virtual void DoProgress(float value){
cout << ".";
}
};

模式定义:

  • 定义对象间的一种一对多(变化)的依赖关系,以便当一个对象的状态发生变化时,所有依赖它的对象都可以得到通知并自动更新。

observer :IProgress

update:doProgess

attach : addiprogess

detach: removeiprogess

notify : noprogess

ConvreteObserver: mainform /console notify

mark

总结:

  • 使用面向对象的抽象,Observer模式使得我们可以独立的改变目标与观察者,从而使二者之间的依赖关系松耦合
  • 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)自动传播
  • 观察者自己决定是否需要订阅通知,目标对象对此一无所知
  • Observer模式基于事件的ui 框架中常用的设计模式,也是MVC模式的一个重要组成部分

Decorator装饰模式

单一职责模式:

  • 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任

  • Decorator

  • Bridge

    动机:

  • 某些情况下可能过度使用继承来扩展对象的功能,由于继承为类型引入的静态特质(FileStream:read(),NetworkStream::read()),使得这种扩展方式缺乏灵活性,并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。

  • 如何时对象功能的扩展能够根据需要来动态的实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?

mark

  • 编译时一样,运行时不一样,多态
  • 装饰
  • CryoFileSyream/BufferedFileStream 不一定要继承 FileStream,不是一个增长方向
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
//业务操作
class Stream{
public
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;
virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};
//扩展操作
class CryptoFileStream :public FileStream{
public:
virtual char Read(int number){

//额外的加密操作...
FileStream::Read(number);//读文件流

}
virtual void Seek(int position){
//额外的加密操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
}
};
class CryptoNetworkStream : :public NetworkStream{
public:
virtual char Read(int number){
//额外的加密操作...
NetworkStream::Read(number);//读网络流
}
virtual void Seek(int position){
//额外的加密操作...
NetworkStream::Seek(position);//定位网络流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
NetworkStream::Write(data);//写网络流
//额外的加密操作...
}
};
class CryptoMemoryStream : public MemoryStream{
public:
virtual char Read(int number){

//额外的加密操作...
MemoryStream::Read(number);//读内存流
}
virtual void Seek(int position){
//额外的加密操作...
MemoryStream::Seek(position);//定位内存流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
MemoryStream::Write(data);//写内存流
//额外的加密操作...
}
};
class BufferedFileStream : public FileStream{
//...
};

class BufferedNetworkStream : public NetworkStream{
//...
};

class BufferedMemoryStream : public MemoryStream{
//...
}

class CryptoBufferedFileStream :public FileStream{
public:
virtual char Read(int number){

//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(byte data){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};
void Process(){

//编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();

BufferedFileStream *fs2 = new BufferedFileStream();

CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();

}

mark

  • 组合替代了继承
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
//业务操作
class Stream{

public
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;

virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
};
//扩展操作
class CryptoStream: public Stream //继承Stream 为了virtual 接口统一
{
Stream* stream;//...
public:
CryptoStream(Stream* stm):stream(stm){
}
virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};
class BufferedStream : public Stream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):stream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2);
}
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 Stream{
public
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;

virtual ~Stream(){}
};
//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}
};
class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}
};
class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}
};
//扩展操作
DecoratorStream: public Stream{
protected: ////protected????
Stream* stream;//...
DecoratorStream(Stream * stm):stream(stm){
}
};
class CryptoStream: public DecoratorStream {
public:
CryptoStream(Stream* stm):DecoratorStream(stm)//调用基类构造器
{

}
virtual char Read(int number){
//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};

class BufferedStream : public DecoratorStream{
Stream* stream;//...
public:
BufferedStream(Stream* stm):DecoratorStream(stm){
}
//...
};
void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2);
}

模式定义:

  • 动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。

mark

总结:

  • 通过采用组合而非继承的方法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。

  • Decorator类在接口上表现为is-a component继承关系,即Decorator类继承了component类所具有的接口。但在实现上又表现为has-a component 组合关系,即Decorator类又使用了另外一个Component类

  • Decorator模式的目的并非解决“多子类衍生的多继承问题”,应用的要点在于解决“主题类在多个方向上的扩展功能”,是为装饰的含义。

  • 看到一个类,父类为一个类,同时子类里还有一个父类的字段,怀疑为装饰模式

    • 继承父类 为了接口规范
    • 有父类字段,为了支持实现
  • 1
    2
    3
    4
    5
    6
    DecoratorStream: public Stream{
    protected: ////protected????
    Stream* stream;//...
    DecoratorStream(Stream * stm):stream(stm){
    }
    };

Bridge桥模式

mark

动机:

  • 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化。
  • 如何应对这种多维度的变化,如何利用面向对象技术来使得类型可以轻松的沿着两个乃至多个方向变化,而不引入额外的复杂度。

Lite 和Lite,perfect和perfect 重合

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
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;

virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台实现n 类的个数1+n+m*n
class PCMessagerBase : public Messager{
public:

virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象m
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){

PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){

PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){

MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){

MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){

MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){

MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){

MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){

MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
  • Messager 构造函数 增加对Messager的初始化
  • 子类构造函数调用Messager的构造函数
  • 如果子类里有同样的字段,把这个字段往父类扔,protected:
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
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;

virtual ~MessagerImp(){}
};


//平台实现 n
class PCMessagerImp : public MessagerImp{
public:

virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};

class MobileMessagerImp : public MessagerImp{
public:

virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};



//业务抽象 m

//类的数目:1+n+m

class MessagerLite :public Messager {


public:

virtual void Login(string username, string password){

messagerImp->Connect();
//........
}
virtual void SendMessage(string message){

messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){

messagerImp->DrawShape();
//........
}
};



class MessagerPerfect :public Messager {


public:

virtual void Login(string username, string password){

messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){

messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){

messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};

void Process(){
//运行时装配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new Messager(mImp);
}

模式定义:

  • 将抽象部分(业务功能)与实现部分(平台分离)分离,使它们都可以独立变化

mark

总结:

  • Bridge 使用对象间的组合关系解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,即子类化它们
  • Bridge 有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(一个类只有一个变化的原因),复用性差。Bridge是比多继承方案更好的解决方案
  • Bridge模式的应用一般在两个非常强的变化维度,有时一个类有多余两个的变化维度,这时剋使用Bridge的扩展模式。

Factory Method 工厂模式

对象创建模式:

  • 通过对象创建模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作
  • Fcatory method
  • Abstract Factory
  • Prototype
  • Builder

动机:

  • 在软件系统中,经常面临创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化
  • 如何应对这种变化,如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种具体对象创建工作的紧耦合

违背依赖倒置原则,

编译时依赖,编译时通过,MainFrom 编译时,需要依赖于BinarySplitter的存在。`

创建对象:

  • new
  • BinarySplitter bs();
  • 通过一个函数返回一个对象
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 ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//////////////////////////////////////
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
ISplitter * splitter=
new BinarySplitter();//依赖具体类
splitter->split();
}
};
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
//具体类
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new BinarySplitter();
}
};
class TxtSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new TxtSplitter();
}
};
class PictureSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new PictureSplitter();
}
};
class VideoSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new VideoSplitter();
}
};
///////////////////////////////////////////////////////
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};
/////////////////////////////////////////////////////////////
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory){
this->factory=factory;
}
void Button1_Click(){
ISplitter * splitter=
factory->CreateSplitter(); //多态new
splitter->split();
}
};

模式定义:

  • 定义一个用于创建对象的接口,让子类决定实例化哪个类,Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。

Product: ISplitter

ConcreteProduct: BinarySplitter/TxtSplitter/PictureSplitter

Creator: SplitterFactory

ConcreteCreator:BinarySplitterFactory/TxtSplitterFactory/PictureSplitterFactory

mark

总结:

  • Factory Method 模式用于隔离对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱
  • Factory Method 模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展而非更改)的策略,较好的解决了这种紧耦合关系。
  • Factory Method 模式解决单个对象的需求变化。缺点在于要求创建方法/参数相同.

Abstract Factory抽象工厂模式

动机

  • 面临一系列相互依赖的对象的创建工作,同时由于需求的变化,往往存在更多系列对象的创建工作。
  • 如何应对这种变化,如何绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和这种多系列具体对象创建工作的紧耦合。

面临多种数据库的变化,new() 不适合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class EmployeeDAO{

public:
vector<EmployeeDO> GetEmployees(){
SqlConnection* connection =
new SqlConnection();
connection->ConnectionString = "...";

SqlCommand* command =
new SqlCommand();
command->CommandText="...";
command->SetConnection(connection);

SqlDataReader* reader = command->ExecuteReader();
while (reader->Read()){
}
}
};
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

//数据库访问有关的基类
class IDBConnection{

};
class IDBConnectionFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
};


class IDBCommand{

};
class IDBCommandFactory{
public:
virtual IDBCommand* CreateDBCommand()=0;
};


class IDataReader{

};
class IDataReaderFactory{
public:
virtual IDataReader* CreateDataReader()=0;
};


//支持SQL Server
class SqlConnection: public IDBConnection{

};
class SqlConnectionFactory:public IDBConnectionFactory{

};

class SqlCommand: public IDBCommand{

};
class SqlCommandFactory:public IDBCommandFactory{

};

class SqlDataReader: public IDataReader{

};
class SqlDataReaderFactory:public IDataReaderFactory{

};
//支持Oracle
class OracleConnection: public IDBConnection{

};
class OracleCommand: public IDBCommand{
};

class OracleDataReader: public IDataReader{
};

class EmployeeDAO//connectioncommandreader 三者是要同一个数据库类型
{
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDataReaderFactory* dataReaderFactory;

public:
vector<EmployeeDO> GetEmployees(){

IDBConnection* connection =
dbConnectionFactory->CreateDBConnection();
connection->ConnectionString("...");

IDBCommand* command =
dbCommandFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性

IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
};
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

//数据库访问有关的基类
class IDBConnection{
};
class IDBCommand{
};
class IDataReader{
};
class IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持SQL Server
class SqlConnection: public IDBConnection{
};
class SqlCommand: public IDBCommand{
};
class SqlDataReader: public IDataReader{
};
class SqlDBFactory:public IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持Oracle
class OracleConnection: public IDBConnection{

};
class OracleCommand: public IDBCommand{

};
class OracleDataReader: public IDataReader{

};
class EmployeeDAO{
IDBFactory* dbFactory;
public:
vector<EmployeeDO> GetEmployees(){
IDBConnection* connection =
dbFactory->CreateDBConnection();
connection->ConnectionString("...");

IDBCommand* command =
dbFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性

IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
};

模式定义:

  • 提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类。

AbstractFactory: IDBFactory

ConcreteFactory1: SqlDBFactory

ConcreteFactory2: OracleDBFactory

AbstractProductA: IDBConnection

AbstractProductB: IDBCommand

mark

总结:

  • 如果没有必要应对多系列对象构建的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂
  • 系列对象指的是在某一特定系列下的对象之间有相互依赖、相互作用的关系。不同系列的对象之间不能相互依赖。
  • Abstract Factory 主要在于应对新系列的需求变化。其缺点在于难以应对新对象的需求变动。

Prototype原型模式

  • 和BUILD模式用的少
  • 对象创建模式

通过拷贝构造函数绕过new

动机:

  • 在软件系统中,经常面临“某些结构复杂的对象”的创建工作,由于需求的变化,这些对象经常面临者剧烈的变化,但是它们却拥有比较稳定一致的接口
  • 如何应对这种变化?如何向“客户程序”(使用这些对象的程序)隔离出这些易变对象,从而使得”依赖这些易变对象的客户程序“不随着需求改变而改变。
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
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象

virtual ~ISplitter(){}

};
//具体类
class BinarySplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new BinarySplitter(*this);
}
};
class TxtSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new TxtSplitter(*this);
}
};
class PictureSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new PictureSplitter(*this);
}
};
class VideoSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new VideoSplitter(*this);
}
};
////////////////////////////////////
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
ISplitter * prototype=
prototype->clone(); //克隆原型
prototype->split();

delete prototype;
}
};

模式定义:

  • 使用原型实例指定创建对象的种类,然后通过深拷贝这些原型来创建新的对象
  • 工厂方法 new一个对象,对象的method 实现
  • 深拷贝构造函数,

mark

总结:

  • 同样适用于隔离类对象的使用者具体类型(易变类)之间的耦合关系,同样要求这些易变类有稳定的接口。
  • 对于如何创建易变类的实体对象采用原型克隆的方法来做,使得我们可以非常灵活的动态创建拥有某些稳定接口的新对象,所需工具仅仅是注册一个新类的对象即原型,然后在任何需要的地法国Clone
  • Clone方法可以利用某些框架中的序列化来实现深拷贝

Builder构建器模式

动机:

  • 在软件系统中,有时候面临着一个复杂对象的创建工作,其通常由各个福分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法相对稳定
  • 如何应对这种变化,如何提供一种封装机制来隔离出复杂对象的各个部分的变化,从而保持系统中的稳定构建算法不随着需求的改变而改变。

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

class House{
//....
};

class HouseBuilder {
public:
House* GetResult(){
return pHouse;
}
virtual ~HouseBuilder(){}
protected:

House* pHouse;
virtual void BuildPart1()=0;
virtual void BuildPart2()=0;
virtual void BuildPart3()=0;
virtual void BuildPart4()=0;
virtual void BuildPart5()=0;

};

class StoneHouse: public House{

};

class StoneHouseBuilder: public HouseBuilder{
protected:

virtual void BuildPart1(){
//pHouse->Part1 = ...;
}
virtual void BuildPart2(){

}
virtual void BuildPart3(){

}
virtual void BuildPart4(){

}
virtual void BuildPart5(){

}

};


class HouseDirector{

public:
HouseBuilder* pHouseBuilder;

HouseDirector(HouseBuilder* pHouseBuilder){
this->pHouseBuilder=pHouseBuilder;
}

House* Construct(){

pHouseBuilder->BuildPart1();

for (int i = 0; i < 4; i++){
pHouseBuilder->BuildPart2();
}

bool flag=pHouseBuilder->BuildPart3();

if(flag){
pHouseBuilder->BuildPart4();
}

pHouseBuilder->BuildPart5();

return pHouseBuilder->GetResult();
}
};

1542364198157

总结:

  • Build模式主要用于分步骤构建一个复杂的对象。这其中分步骤是一个稳定的算法,而复杂对象的各个部分经常变化
  • 变化在哪里,封装在哪里—–Builder模式主要在于应对复杂对象的各个部分的频繁需求变动。其缺点在于难以应对分步骤构建算法的需求变动
  • 注意不同语言中构造器内调用虚函数的差别(c++ VS C#)
  • 派生类中可以通过派生类对象访问基类的protected成员

Singleton 单件模式

对象性能模式:

  • 面向对象带来的成本,虚函数
  • Singleton
  • Flyweight

动机:

  • 特殊的类,只存在一个实例
  • 绕过常规的构造器,提供一种机制来保证一个类只有一个实例
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


class Singleton{
private:
Singleton();
Singleton(const Singleton& other);
public:
static Singleton* getInstance();
static Singleton* m_instance;
};

Singleton* Singleton::m_instance=nullptr;

//线程非安全版本
Singleton* Singleton::getInstance() {
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}


//同时读操作不需要加锁

//线程安全版本,但锁的代价过高
Singleton* Singleton::getInstance() {
Lock lock;
if (m_instance == nullptr) {
m_instance = new Singleton();
}
return m_instance;
}


//双检查锁,但由于内存读写reorder不安全
//reorder
//分配内存,构造器,内存地址赋值m_instance 三个顺序有可能reorder
//分配内存 内存地址赋值m_instance(thiead b 返回m_instance) 构造器
Singleton* Singleton::getInstance() {

if(m_instance==nullptr)// 都是读操作
{
Lock lock;
if (m_instance == nullptr) {
50 m_instance = new Singleton();
}
}
return m_instance;
}

//C++ 11版本之后的跨平台实现 (volatile)
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;

Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);//获取内存fence
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release);//释放内存fence
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}

模式定义:

  • 保证一个类只有一个实例,并提供一个该例的全局访问点

1542368309714

总结:

  • Singleton模式中的实例构造器可以设置为protected以允许子类派生。
  • 一般不要支持拷贝构造和Clone接口
  • 多线程下的安全的Singletong,注意双检查锁的正确实现。

Flyweight 享元模式

  • 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行时代价-主要指内存需求方面的代价。
  • 如何在避免大量细粒度对象问题的同时,让外部客户程序仍然能够透明地使用面向对象的方式来操作。
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 Font{
private:
string key;
public:
Font(const string& key){

}

};
class FontFactory{
private:
map <string,Font*> fontpool;
public:
Font* GetFont(const string& key)
{
map<string,Font*>::iterator item=fontpool.find(key);
if(item!=fontpool.end())
{
return fontpool[key];
}
else{
Font* font=new Font(key);
fontpool[key]=font;
return font;
}
}
void clear()
{

}
};

模式定义:

  • 运用共享技术有效支持大量细粒度对象

总结:

  • 解决面向对象的代价问题
  • 采用共享对象的做法来降低系统中对象的个数,降低细粒度给系统带来的内存压力,在具体事项方面,注意对象状态的处理,尽可能只读

Facade 门面模式

接口隔离模式:

  • 在组建构建过程中,某些接口之间直接的依赖会带来很多问题,采用添加一层间接(稳定)的接口,来隔离本来互相基民关联的接口是一种常见的解决方案。

  • Facade

  • Proxy

  • Adapter

  • Mediator

动机:

  • A方案的问题在于客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。
  • 如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦。

模式定义:

  • 为子系统中的一组接口提供一个一致(稳定)的界面,Facade定义了一个高层接口,使得这一子系统更加容易使用(复用)。

总结:

  • 从客户程序角度来看,Facade模式简化了整个组建系统的接口,对于组建内部与外部客户程序来说,达到了一种解耦的效果-内部子系统的任何变化不会影响到Facade接口的变化。
  • Facade模式更注重从架构的层次去看整个系统,而不是单个类的层次,更多时候是一种架构设计模式。
  • 并非一个集装箱,可以任意放进任何多个对象。Facade中组建的内部应该是“相互耦合关系比较大的一系列组建件”,而不是一个简单的功能集合。

代理模式

动机:

  • 有些对象某些原因(对象创建的开销很大,某些操作需要安全控制,需要进程外的访问),直接访问会给使用者、系统结构带来很多麻烦
  • 如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。

模式定义:

  • 为其它对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。

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
class ISubject{
public:
virtual void process();
};


class RealSubject: public ISubject{
public:
virtual void process(){
//....
}
};

class ClientApp{

ISubject* subject;

public:

ClientApp(){
subject=new RealSubject();
}

void DoTask(){
//...
subject->process();

//....
}
};
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
class ISubject{
public:
virtual void process();
};

//Proxy的设计 很复杂 多工具自动生成
class SubjectProxy: public ISubject{

public:
virtual void process(){
//对RealSubject的一种间接访问
//....
}
};
class ClientApp{
ISubject* subject;
public:

ClientApp(){
subject=new SubjectProxy();
}

void DoTask(){
//...
subject->process();
//....
}
};

总结:

Adapter适配器

动机:

  • 由于应用环境的变化,常常需要将“一些现存的对象”放到新的环境中去使用,但是新环境要求的接口是这些现存对象所不满足的
  • 如何应对这种“迁移的变化”?如何技能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?

模式定义:

  • 将一个类的就转成客户想要的接口
  • 组合/

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
//目标接口(新接口)
class ITarget{
public:
virtual void process()=0;
};

//遗留接口(老接口)
class IAdaptee{
public:
virtual void foo(int data)=0;
virtual int bar()=0;
};

//遗留类型
class OldClass: public IAdaptee{
//....
};

//对象适配器
class Adapter: public ITarget{ //继承
protected:
IAdaptee* pAdaptee;//组合

public:

Adapter(IAdaptee* pAdaptee){
this->pAdaptee=pAdaptee;
}

virtual void process(){
int data=pAdaptee->bar();
pAdaptee->foo(data);
}

};
//类适配器
class Adapter: public ITarget,
protected OldClass{ //多继承
}
int main(){
IAdaptee* pAdaptee=new OldClass();

ITarget* pTarget=new Adapter(pAdaptee);
pTarget->process();

}

class stack{
deqeue container;

};

class queue{
deqeue container;

};

总结:

  • 主要应用于“希望复用一些现存的类,但是接口又与复用环境不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
  • 两种实现结构:
    • 对象适配器,对象组合
    • 类适配器,多继承,不推荐

中介者模式

动机:

  • 多个对象互相并联交互,多个对象之间维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。
  • 使用一种中介对象来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好抵御变化。

定义:

  • 用一个中介对象来封装(封装变化)一系列的对象交互。中介者使各对象不需要显式的相互引用(编译时依赖->运行时依赖),从而使其耦合松散(管理变化),而且可以独立地改变它们之间的交互。

  • concretecolleague1和concretecolleague2本来存在依赖关系

  • concretecolleague1和concretecolleague2 依赖Mediator,而Mediator依赖Colleague,使得concretecolleague1和concretecolleague2不相互依赖

总结:

  • 将多个对象间复杂的关联关系解耦,Mediator模式将多个对象间的控制逻辑进行集中管理,变“多个对象互相关联”为多个对象和一个中介者关联,简化了系统的维护,抵御了可能的变化。
  • 随着控制逻辑的变化,Mediator具体对象的实现可能相当复杂。可以对Mediator对象进行分界处理
  • Facade模式是解耦系统间(单向)的对象关联关系;Mediator模式解耦系统内各个对象之间(双向)的并联关系。

State 状态模式

状态变化模式:

  • 在组件构建过程中,某些对象的状态经常面临变化,如何对状态变化进行有效的管理?同时又维持高层模块的稳定?
  • State
  • Memento

动机:

  • 某些对象的状态如果改变,其行为也会随之而发生变化,eg(文档处于只读状态其支持的行为和读写的状态支持的行为就可能完全不同)
  • 如何在运行时根据对象的状态来透明的更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合。
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
//多个 if/else 
//增加一个时,违背开放封闭原则
enum NetworkState
{
Network_Open,
Network_Close,
Network_Connect,
};
class NetworkProcessor{

NetworkState state;

public:
void Operation1(){
if (state == Network_Open){

//**********
state = Network_Close;
}
else if (state == Network_Close){

//..........
state = Network_Connect;
}
else if (state == Network_Connect){

//$$$$$$$$$$
state = Network_Open;
}
}
public void Operation2(){

if (state == Network_Open){

//**********
state = Network_Connect;
}
else if (state == Network_Close){

//.....
state = Network_Open;
}
else if (state == Network_Connect){

//$$$$$$$$$$
state = Network_Close;
}
}

public void Operation3(){

}
};
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
class NetworkState{

public:
NetworkState* pNext;
virtual void Operation1()=0;
virtual void Operation2()=0;
virtual void Operation3()=0;

virtual ~NetworkState(){}
};


class OpenState :public NetworkState{

static NetworkState* m_instance;
public:
static NetworkState* getInstance(){
if (m_instance == nullptr) {
m_instance = new OpenState();
}
return m_instance;
}

void Operation1(){

//**********
pNext = CloseState::getInstance();
}

void Operation2(){

//..........
pNext = ConnectState::getInstance();
}

void Operation3(){

//$$$$$$$$$$
pNext = OpenState::getInstance();
}


};

class CloseState:public NetworkState{ }
//...


class NetworkProcessor{

NetworkState* pState;

public:

NetworkProcessor(NetworkState* pState){

this->pState = pState;
}

void Operation1(){
//...
pState->Operation1();
pState = pState->pNext;
//...
}

void Operation2(){
//...
pState->Operation2();
pState = pState->pNext;
//...
}

void Operation3(){
//...
pState->Operation3();
pState = pState->pNext;
//...
}

};

context:networkprocessor

模式定义:

  • 允许对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。

总结:

  • state模式将所有与一个特定状态相关的行为都放入一个state的对象中,在对象状态切换时,切换相应的对象,但同时维持state的接口,实现了具体操作和状态切换之间的解耦
  • 为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——即要么彻底转换过来,要么不转换。
  • 如果state对象没有实例变量,那么各个上下文可以共享同一个state对象(singleton),节省开销。

Memento 备忘录模式

动机:

  • 某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些共有接口来让其他对象得到对象的状态,便会暴漏对象的细节实现。
  • 如何实现对象状态的良好保存和恢复?同时又不会破坏对象本身的封装性。
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

class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};



class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};



int main()
{
Originator orginator;

//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();

//... 改变orginator状态

//从备忘录中恢复
orginator.setMomento(memento);

}

总结:

  • 备忘录存储原发器对象的内部状态,在需要时回复原发器的状态
  • Memento核心为信息隐藏,即Originator需要向外隐藏信息,保持其封装性,但同时有需要将状态保持到外界Memento
  • 多采用对象序列化支持实现Memento

组合模式

数据结构模式:

  • 组件在内部有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大的破坏组件的复用。这时候将这些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,行之有效。
  • Composite
  • Iterator
  • Chain of Responsibility

动机:

  • 某些情况下,客户代码过多依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性弊端。
  • 如何将客户代码与复杂的对象容器结构解耦,让对象容器自己来实现自身的复杂结构,从而使客户代码就像简单对象一样来处理复杂的对象容器。

模式定义:

  • 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性(稳定)。
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
#include <iostream>
#include <list>
#include <string>
#include <algorithm>

using namespace std;

class Component
{
public:
virtual void process() = 0;
virtual ~Component(){}
};

//树节点
class Composite : public Component{

string name;
list<Component*> elements;
public:
Composite(const string & s) : name(s) {}

void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
}

void process(){

//1. process current node

//2. process leaf nodes
for (auto &e : elements)
e->process(); //多态调用,处理所有子节点process

}
};

//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {}

void process(){
//process current node
}
};


void Invoke(Component & c){
//...
c.process();
//...
}


int main()
{

Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leat1("left1");
Leaf leat2("left2");

root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1);

root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2);

process(root);
process(leaf2);
process(treeNode3);

}

总结:

  • Composite采用树形结构来实现普遍存在的对象容器,从而将一对多的关系转化为一对一的关系,使得客户代码可以一致的(复用)处理对象和对象容器,无需关心处理的时单个的对象,还是组合的对象容器。
  • 客户代码与复杂的对象容器结构解耦是composite的核心思想,解耦之后,客户代码将与纯粹的抽象接口-而非对象容器的内部实现结构-发生依赖,从而更能应对变化
  • Composite模式在具体实现中,可以让父对象中的子对象方向追溯,如果父对象有频繁的遍历要求可使用缓存技巧来改善效率。

迭代器

  • 数据结构模式

动机:

  • 软件构件过程中,集合对象内部结构常常变化各异。但对于这些集合对象,希望在不暴漏其内部结构的同时,可以让外部客户代码透明的访问其中的元素;同时这种透明遍历也为同一种算法在多种集合对象上进行操作提供了可能。
  • 使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。

模式定义:

  • 提供一种方法顺序访问一个聚合对象中的元素,而又不暴漏(稳定)该对象的内部表示
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
//目前已经过时,虚函数,运行时依赖调用成本大,STL中iterator 泛型编程运行时依赖
template<typename T>
class Iterator
{
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual T& current() = 0;
};

template<typename T>
class MyCollection{

public:

Iterator<T> GetIterator(){
//...
}

};

template<typename T>
class CollectionIterator : public Iterator<T>{
MyCollection<T> mc;
public:

CollectionIterator(const MyCollection<T> & c): mc(c){ }

void first() override {

}
void next() override {

}
bool isDone() const override{

}
T& current() override{

}
};
void MyAlgorithm()
{
MyCollection<int> mc;

Iterator<int> iter= mc.GetIterator();

for (iter.first(); !iter.isDone(); iter.next()){
cout << iter.current() << endl;
}
}

总结:

  • 迭代对象:访问一个聚合对象的内容,而无需暴漏它的内部表示
  • 迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作
  • 迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题

职责链模式

动机:

  • 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能由一个接受者,如果显示指定,将不可避免的带来请求发送者与接受者的紧耦合
  • 如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使二者解耦。

模式定义:

  • 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理完为止。
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
#include <iostream>
#include <string>

using namespace std;

enum class RequestType
{
REQ_HANDLER1,
REQ_HANDLER2,
REQ_HANDLER3
};

class Reqest
{
string description;
RequestType reqType;
public:
Reqest(const string & desc, RequestType type) : description(desc), reqType(type) {}
RequestType getReqType() const { return reqType; }
const string& getDescription() const { return description; }
};

class ChainHandler{

ChainHandler *nextChain;
void sendReqestToNextHandler(const Reqest & req)
{
if (nextChain != nullptr)
nextChain->handle(req);
}
protected:
virtual bool canHandleRequest(const Reqest & req) = 0;
virtual void processRequest(const Reqest & req) = 0;
public:
ChainHandler() { nextChain = nullptr; }
void setNextChain(ChainHandler *next) { nextChain = next; }


void handle(const Reqest & req)
{
if (canHandleRequest(req))
processRequest(req);
else
sendReqestToNextHandler(req);
}
};


class Handler1 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER1;
}
void processRequest(const Reqest & req) override
{
cout << "Handler1 is handle reqest: " << req.getDescription() << endl;
}
};

class Handler2 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER2;
}
void processRequest(const Reqest & req) override
{
cout << "Handler2 is handle reqest: " << req.getDescription() << endl;
}
};

class Handler3 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER3;
}
void processRequest(const Reqest & req) override
{
cout << "Handler3 is handle reqest: " << req.getDescription() << endl;
}
};

int main(){
Handler1 h1;
Handler2 h2;
Handler3 h3;
h1.setNextChain(&h2);
h2.setNextChain(&h3);

Reqest req("process task ... ", RequestType::REQ_HANDLER3);
h1.handle(req);
return 0;
}

总结:

  • 应用场合在于“一个请求可能有多个接受者,但是最后真正的接受者只有一个”,这时候请求发送者与接受者的耦合有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦
  • 应用职责链之后,对象的职责分派将更具灵活性,可以在运行时动态添加/修改请求的处理指责
  • 如果请求传递到职责链的末尾得不到处理,应该有一个合理的缺省机制,这也是每一个接受对象的责任,而不是发出请求的对象的责任。

命令模式

行为变化模式:

  • 组件行为的变化经常导致组建本身剧烈变化。将组件的行为和组建本身进行解耦,从而支持组建行为的变化,实现两者之间的松耦合
  • Command
  • Visitor

动机:

  • 软件构建过程中,“行为请求者”和行为实现者通常呈现一种紧耦合,但在某些场合,比如需要对行为进行“记录、撤销/重(undo/redo) 事务”等处理,这种无法抵御变化的紧耦合不合适
  • 如何将行为请求者与行为实现者解耦?将一组行为抽象为对象,实现两者之间的松耦合。

模式定义:

  • 将请求封装为对象,从而使的用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
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
#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();

}

总结:

  • 在其他语言应用广泛 JAVA,泛型编程已经更好的解决了。

Visitor 访问模式

动机:

  • 由于需求的变化,某些类层次的结构中常常需要添加新的行为(方法),如果直接在基类中修改,常常给子类带来繁重的变更负担,违背扩展封闭原则
  • 如何在不更改类层次结构的前提下,在运行时根据需要透明的为类层次结构上的各个类动态添加新的操作,从而避免上述问题

已经开发完成的情况下。

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
#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;
}

模式定义:

  • 表示一个作用于某对象结构(Element/ElementA/ElementB)中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。isitor

Visitor===Visitor

ConcreteVisitor1===Visitor1

Visitor 需要知道Element子类的个数,具体类型,常常满足不了,就不能用

总结:

  • Visitor通过双重分发(double dispatch)实现在不更改(不添加新的操作-编译时)Element类层次结构的前提下,在运行时透明的为类层次结构上的各个类动态添加新的操作(支持变化)

  • 双重分发即Visitor模式中间包括两个多态分发(多态机制):第一个为acccept方法的多态解析,第二个为visitElementX方法的多态辨析

  • 最大缺点在于扩展类层次结构(增加新的Element子类),会导致Visitor类的改变,因此,Visitor模式适用于Element类层次结构稳定,而其中的操作却经常改动的情形。

Interpreter解析器

领域规则模式:

  • 某些变化虽然频繁,可以抽象为规则。结合特定领域,将问题抽象为语法规则,从而给出在该领域下的一般性解决方案

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

#include <iostream>
#include <map>
#include <stack>

using namespace std;

class Expression {
public:
virtual int interpreter(map<char, int> var)=0;
virtual ~Expression(){}
};

//变量表达式
class VarExpression: public Expression {

char key;

public:
VarExpression(const char& key)
{
this->key = key;
}

int interpreter(map<char, int> var) override {
return var[key];
}

};

//符号表达式
class SymbolExpression : public Expression {

// 运算符左右两个参数
protected:
Expression* left;
Expression* right;

public:
SymbolExpression( Expression* left, Expression* right):
left(left),right(right){

}

};

//加法运算
class AddExpression : public SymbolExpression {

public:
AddExpression(Expression* left, Expression* right):
SymbolExpression(left,right){

}
int interpreter(map<char, int> var) override {
return left->interpreter(var) + right->interpreter(var);
}

};

//减法运算
class SubExpression : public SymbolExpression {

public:
SubExpression(Expression* left, Expression* right):
SymbolExpression(left,right){

}
int interpreter(map<char, int> var) override {
return left->interpreter(var) - right->interpreter(var);
}

};



Expression* analyse(string expStr) {

stack<Expression*> expStack;
Expression* left = nullptr;
Expression* right = nullptr;
for(int i=0; i<expStr.size(); i++)
{
switch(expStr[i])
{
case '+':
// 加法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new AddExpression(left, right));
break;
case '-':
// 减法运算
left = expStack.top();
right = new VarExpression(expStr[++i]);
expStack.push(new SubExpression(left, right));
break;
default:
// 变量表达式
expStack.push(new VarExpression(expStr[i]));
}
}

Expression* expression = expStack.top();

return expression;
}

void release(Expression* expression){

//释放表达式树的节点内存...
}

int main(int argc, const char * argv[]) {


string expStr = "a+b-c+d-e";
map<char, int> var;
var.insert(make_pair('a',5));
var.insert(make_pair('b',2));
var.insert(make_pair('c',1));
var.insert(make_pair('d',6));
var.insert(make_pair('e',10));


Expression* expression= analyse(expStr);

int result=expression->interpreter(var);

cout<<result<<endl;

release(expression);

return 0;
}

模式定义:

  • 给定一个语言,定义它的文法表示,并定义一种解释器,解释语言中的句子

设计模式总结

管理变化,提高复用

  • 依赖倒置原则 DIP
  • 开放封闭原则 OCP
  • 单一职责原则SRP
  • ListKov替换原则LSP
  • 接口隔离模式ISP
  • 对象组合优于类继承
  • 封装变化点
  • 面向接口编程

文章目录
  1. 1. 设计模式
    1. 1.1. 设计模式简介
    2. 1.2. 面向对象设计原则
    3. 1.3. 模板方法
    4. 1.4. 策略模式
    5. 1.5. Observer观察者模式
    6. 1.6. Decorator装饰模式
    7. 1.7. Bridge桥模式
    8. 1.8. Factory Method 工厂模式
    9. 1.9. Abstract Factory抽象工厂模式
    10. 1.10. Prototype原型模式
    11. 1.11. Builder构建器模式
    12. 1.12. Singleton 单件模式
    13. 1.13. Flyweight 享元模式
    14. 1.14. Facade 门面模式
    15. 1.15. 代理模式
    16. 1.16. Adapter适配器
    17. 1.17. 中介者模式
    18. 1.18. State 状态模式
    19. 1.19. Memento 备忘录模式
    20. 1.20. 组合模式
    21. 1.21. 迭代器
    22. 1.22. 职责链模式
    23. 1.23. 命令模式
    24. 1.24. Visitor 访问模式
    25. 1.25. Interpreter解析器
    26. 1.26. 设计模式总结