Design Pattern

一、面向对象设计原则

依赖倒置原则(DIP)

  • 高层模块(稳定)不应该依赖(编译时依赖)于底层模块(变化),二者都应该依赖于抽象(稳定)。
  • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。

开放封闭原则

  • 对拓展开放,对更改封闭
  • 类模块是可扩展的,但是不可修改。

单一职责原则(SRP)

  • 一个类应该仅有一个引起它变化的原因。
  • 变化的方向隐含着类的责任。

Liskov替换原则(LSP)

  • 子类必须能够替换它们的基类(IS-A)。
  • 继承表达类型抽象

接口隔离原则(ISP)

  • 不应该强迫客户程序依赖它们不用的方法。
  • 接口应该小而完备。

优先使用组合而不是继承

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

封装变化点

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

针对接口编程,而不是针对实现编程

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

二、模板方法

Motivation: 如何在确定稳定操作结构的前提下,灵活应对各个子步骤的变化或者晚期实现需求?

Definition: 定义一个操作中的算法骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义overeide该算法的某些特定步骤。

Case1:

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 Lib{
public:
void step1(){}
void step3(){}
void step5(){}
};

class App {
public:
bool step2(){}
void step4(){}
};

int main(){
Lib lib();
App app();
lib.step1();
if(app.step2()) {
lib.step3();
}

for (int i = 0; i < 4; ++ i) {
app.step4();
}
lib.step5();
return 0;
}

Case2:

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
class Lib{
public:

// Stable template method
void run(){
step1();
if(step2()) { // Support for changes due to Polymorphism
step3();
}

for (int i = 0; i < 4; ++ i) {
step4(); // Support for changes due to Polymorphism
}
step5();
}
virtual ~Lib(){}

protected:
void step1(){}
void step3(){}
void step5(){}

virtual bool step2(){}
virtual void step4(){}
};

class App : public Lib{
protected:
virtual bool step2() = 0;
virtual void step4() = 0;
};

int main(){
Lib* lib = new App();
lib->run();
delete lib;
return 0;
}

Conclution:
- Make it a habit to recognize which function is variable and which is stable. - Template method is common. - The virtual functions are often set to protected.

三、策略模式

Motivaiton: 某些对象的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使的对象很复杂。

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

Case1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum TaxBase {
CN_Tax,
US_Tax,
DE_Tax,
// change: TR_Tax
};

class SalesOrder{
TaxBase tax;
public:
double CalculateTax(){
if (tax == CN_Tax) {}
else if (tax == US_Tax) {}
else if (tax == DE_Tax) {}
// change: else if (tax == FR_Tax) {}
}
}

Case2

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
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) {}
};

// extend:
// 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;
}

double CalculateTax() {
Context conttext();

double val = strategy->Calculate(context);
}
}

Conclusion:

  • Strategy pattern provides a series of re-used algorithms to make switching alogrithms more convenient.
  • Strategy pattern can substitude condition statement unless the conditions are countable.
  • Single instance pattern can be used to reduce overhead

四、观察者模式

Motivation: - 为某些对象简历通知依赖关系,即,一个对象的状态发生改变,所有的依赖对象都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。 - 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件体系结构的松耦合。

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

Case1: Betray DIP, and the progressBar might be changed with aternaltive form in the future.

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
class FileSplitter {
string m_filePath;
int m_fileNumber;
ProgressBar* m_progressBar; // New requirement

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) {
// ...
if (m_progressBar) {
m_progressBar->setValue((i + 1) / m_fileNumber); // Update progressbar
}
}
}
}

class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar; // New requirement

public:
void Button1_Click() {
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());

FileSplitter splitter(filePath, number, progressBar);
splitter.split();
}
}

Case2:

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

// Observer
class IProgress{
public:
virtual void DoProgress(float value) = 0;
virtual ~IProgress(){}
}

class FileSplitter {
string m_filePath;
int m_fileNumber;
// ProgressBar* m_progressBar;
list<IProgress*> m_iprogressList; // 抽象通知机制,支持多个观察者

public:
FileSplitter(const string & filePath, int fileNumber) :
m_filePath(filePath),
m_fileNumber(fileNumber) {}

void add_IProgress(IProgress* iprogress) {
m_iprogressList.add(iprogress);
}

void remove_IProgress(IProgress* iprogress) {
m_iprogressList.remove(iprogress);
}

void split() {
// 1. 读取大文件

// 2.分批次向小文件写入
for (int i = 0; i < m_fileNumber; ++i) {
// ...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue); // 发送通知
}
}

protected:
void onProgress(float value) {
for (auto &iter : m_iprogressList) {
iter->DoProgress(progressValue); // Update progressbar
}
}
};

class MainForm : public Form, public IProgress // C++ 多继承一般第一个是父类,其他的是接口
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar; // New requirement

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();
}

virtual void DoProgress(float value) {
progressBar->setValue(value);
}
}

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

Conclusion:

  • We can change objective and observer separately with observer pattern to loosen coupling of objective and observer.
  • 目标发送通知时,无需指定观察者,通知会自动传播。
  • 观察者自己决定是否需要订阅通知,目标对象对此一无所知。

五、装饰模式

Motivation: 过度使用继承来拓展对象的功能,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多,各种子类的组合会导致更多子类的膨胀。

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

Case1: \(1 + n + n * (2^m - 1)\)

其中\((2^m - 1) = C_m^1 + \cdots + C_m^m\)

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
class Stream {
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(int data) = 0;
};

class FileStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

class NetworkStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

class MemoryStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

// 拓展操作
class CryptoFileStream : public FileStream {
public:
virtual char Read(int number) {
FileStream::Read(number);
}
virtual char Seek(int position) {
FileStream::Seek(position);
}
virtual char Write(byte data) {
FileStream::Write(data);
}
};

class CryptoNetworkStream : public NetworkStream {
public:
virtual char Read(int number) {
NetworkStream::Read(number);
}
virtual char Seek(int position) {
NetworkStream::Seek(position);
}
virtual char Write(byte data) {
NetworkStream::Write(data);
}
};

class CryptoMemoryStream : public MemoryStream {
public:
virtual char Read(int number) {
MemoryStream::Read(number);
}
virtual char Seek(int position) {
MemoryStream::Seek(position);
}
virtual char Write(byte data) {
MemoryStream::Write(data);
}
};

class BufferedFileStream : public FileStream {};

class BufferedNetworkStream : public NetworkStream {};

class BufferedMemoryStream : public MemoryStream {};

class CryptoBufferedFileStream : public FileSstream {
public:
virtual char Read(int number) {
FileStream::Read(number);
}
virtual char Seek(int position) {
FileStream::Seek(position);
}
virtual char Write(byte data) {
FileStream::Write(data);
}
}

void Process() {
// 编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 = new CryptoBufferedFileStream();
}

Case2: \(1 + n + 1 + m\)

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
class Stream {
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(int data) = 0;
};

class FileStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

class NetworkStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

class MemoryStream : public Stream {
public:
virtual char Read(int number) {}
virtual char Seek(int position) {}
virtual char Write(char data) {}
};

// 拓展操作

DecoratorStream : public Stream {
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 char Seek(int position) {
stream->Seek(position);
}
virtual char Write(byte data) {
stream->Write(data);
}
};

class BufferedStream : public DecoratorStream { // 继承为了接口规范
public:
BufferedStream(Stream *stm): DecoratorStream(stm) {}

virtual char Read(int number) {
stream->Read(number);
}
virtual char Seek(int position) {
stream->Seek(position);
}
virtual char Write(byte data) {
stream->Write(data);
}
};

void Process() {

// 运行时装配
FileStream* s1 = new FileStream();
CryptoStream* s2 = new CryptoStream(s1);
BufferedSteam1* s3 = new BufferedStream(s1);
BufferedSteam1* s4 = new BufferedStream(s2); // CryptoBufferedStream
}

Conclusion: - 通过组合而非继承的方法,实现了运行时动态扩展对象功能的能力

六、桥模式

Motivation: 由于某些类型的固有实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化。

Definition: 将抽象部分与实现部分分离,使他们都可以独立地变化。

Case1: \(1 + n + m * n\)

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
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(){}
}

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() {};
}

// 业务抽象
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();
}

Case2: \(1 + n + 1 + m\)

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 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(){}
}

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() {};
}

// 业务抽象
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 MessagerPerfect(mImp);
}

Conclusion:

  • Bridege pattern 使用对象间的组合关系解耦合了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化.

七、工厂方法模式

Motivation:

  • 在软件系统中,经常面临着创建对象的工作,由于需求的变化,需要创建的对象的具体类型经常变化。

  • 绕过常规的对象创建方法(new),提供一种封装机制来避免客户程序和具体对象创建工作的紧耦合。

Definition: 将抽象部分与实现部分分离,使他们都可以独立地变化。

Case1:

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
class ISplitter{
public:
virtual void split() = 0;
virtual ~ISplitter(){}
};

class FileSplitter : public ISplitter{
public:
void split() {

}
}

class BinarySplitter : public ISplitter{

};

class TxtSplitter : public ISplitter{

};

class PictureSplitter : public ISplitter{

};

class VideoSplitter : public ISplitter{

};

class MainForm : public Form
{

public:
void Button1_Click() {
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());

ISplitter * splitter = new FileSplitter(filePath, number); // 依赖具体类,这里写死了是FileSplitter,违反依赖导致原:抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。
splitter->split();
}
}

Case2:

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
class SplitterFactory {
public:
virtual ISplitter* CreateSplitter() = 0;
virtual ~SplitterFactory() {}
};

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 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 VedioSplitterFactory: public SplitterFactory {
public:
virtual ISplitter* CreateSplitter() {
return new VedioSplitter();
}
};

class MainForm : public Form
{
SplitterFactory* factory;
public:

MianForm(SplitterFactory* factory) {
this->factory = factory;
}

void Button1_Click() {

ISplitter* splitter = factory->CreateSplitter();
splitter->split();
}
}

Conclusion:

  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。

  • Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展的策略,较好地解决了这种紧耦合关系。

  • Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。

八、抽象工厂模式

Motivation: 在软件系统中,经常面临着一系列相互依赖的对象的创建工作;同时,由于需求的变化,往往存在更多系统对象的创建工作。

Definition: 提供一个接口,让改接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们具体的类。

Case1:

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
class IBDConnection{

};

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

class IDBCommand{

};

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

class IDataReader{

}

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

class SqlConnectionFactory: public IDBConnectionFactory{

}

class SqlConnection: public IDBConnection{

};

class SqlCommandFactory: public IDBCommandFactory{

}

class SqlCommand: public IDBCommand{

};

class SqlDataReaderFactory: public IDataReaderFactory{

}

class SqlDataReader: public IDataReader{

};

class OracleConnection: public IDBConnection{

};

class OracleCommand: public IDBCommand{

};

class OracleDataReader: public IDataReader{

};



class EmployeeDAO{
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDataReaderFactory* dataReaderFactory;
public:
vector<EmployeeDO> GetEmployees(){
IDBConnection* connection = IDBConnectionFactory->createDBConnection();
connection->ConnectionString("...");

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

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

}
}
}

case2:

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 IBDConnection{

};

class IDBCommand{

};

class IDataReader{

}

class IDBFactory {
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDataReader* CreateIDataReader() = 0;
}

class SqlDBFactory: public IDBFactory{
public:
virtual IDBConnection* CreateDBConnection() = 0;
virtual IDBCommand* CreateDBCommand() = 0;
virtual IDataReader* CreateIDataReader() = 0;
}

class SqlConnection: public IDBConnection{

};

class SqlCommand: public IDBCommand{

};

class SqlDataReader: public IDataReader{

};

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()) {

}
}
}

Conclusion: - 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。

  • “系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列对象之间不能相互依赖。

  • Abstract Factory模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。

原型模式

Motivation: 在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。

Definition: 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

case 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class ISplitter {
public:
virtual ISplitter* clone() = 0;
virtual void split() = 0;
virtual ~ISplitter(){}
};


// 具体类
class BinarySplitter : public ISplitter{
virtual ISplitter* clone() {
return new BinarySplitter(*this);
}
};

class TxtSplitter : public ISplitter{
virtual ISplitter* clone() {
return new TxtSplitter(*this);
}
};

class PictureSplitter : public ISplitter{
virtual ISplitter* clone() {
return new PictureSplitter(*this);
}
};

class VideoSplitter : public ISplitter{
virtual ISplitter* clone() {
return new VideoSplitter(*this);
}
};

class MainForm : public Form
{
ISplitter* prototype; // 原型对象
public:

MianForm(ISplitter* prototype) {
this->prototype = prototype;
}

void Button1_Click() {

ISplitter* splitter = prototype->clone(); // 克隆原型
splitter->split();
}
}

Conclusion: - 什么时候用原型什么时候用工厂?用工厂模式创建对象是否是几个简单的步骤就能创建出来,还是说要考虑对象复杂的中间状态。 - 原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。 - 原型模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象--所需工作仅仅是注册一个新类的对象(即原型),然后再任何需要的地方Clone。 - 原型模式中的Clone方法可以利用某些框架中的序列化来实现深拷贝。

构建器

Motivation: 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

单例模式

Motivation:

  • 在软件系统中,经常有一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。

  • 如何绕过常规的构造器,提供一种机制保证一个类只有一个实例

Definition: 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。

Case1:

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 Singleton {
private:
Singleton();
Singleton(const Singlton& other);
public:
static Singleton* getInstance();
static Singleton* m_instance;
}

Singleton* Singleton::m_instance = nullptr;

// MT non-safe
Sington* Singleton::getInstance() {
if (!m_instance) m_instance = new Singleton();
return m_instnace;
}

// MT safe
Sington* Singleton::getInstance() {
Lock lock;
if (!m_instance) m_instance = new Singleton();
return m_instnace;
}

// double-check lock while reordering non-safe
Sington* Singleton::getInstance() {
if (!m_instance) {
Lock lock;
if (!m_instance) m_instance = new Singleton();
}
return m_instnace;
}

// C++ 11 volatile

std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singtle::m_mutex;

Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire); // acquire fence
if (tmp == nulpptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_oder_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
std::atomic_thread_fence(std::memory_order_release); // release fence
m_instance.store(tmp, std::memory_order_relaxed);
}
}
}

Conclusion:

  • Singleton模式中的实例构造器可以设置为protected

  • Singleton模式一般不要支持拷贝构造函数,因为有可能导致多个对象实例

  • 多线程下安全的Singleton


Design Pattern
http://chenxindaaa.com/Programming/Python/Design Pattern/
Author
chenxindaaa
Posted on
December 2, 2023
Licensed under