编程思想——设计模式

设计模式

  一个模式描述了一个不断发生问题及这个问题的解决方案;模式是前人的设计经验上总结出来的对于一些普遍存在的问题提供的通用解决方案,比如单例模式、观察者模式等;

  软件工程中有很多模式,面向对象常见的有23种设计模式,可以分为创建型(单例),结构型(适配器)和行为型(观察者)模型。设计模式不是万能的,它建立在系统变化点上,哪里有变化哪里就可以用。设计模式是为了解耦合,为了扩展,它通常是演变过来的,需要演变才能准确定位。设计模式是一种软件设计方法,不是标准,面目前大部分框架中都包含了大量的设计模式思想。

  

单例模式

  有些时候,我们需要整个程序中有且只有一个实例,比如系统日志、Windows资源管理器窗口,数据库分配主键等操作。单例的实现思路:

  1. Singleton拥有一个私有的构造函数,确保用户无法通过new直接实例它;
  2. 包含一个静态私有成员变量instance与静态公有方法Instance(),让外部通过Instance()来获取实例;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Singleton.h

class Singleton
{
public:
//只有静态的方法才能访问静态的变量
static const Singleton* getInstance();
static void DoSomething()
{
cout << "Do Something" << endl;
}
// 将构造和析构函数私有化,防止外部访问
private:
Singleton();
~Singleton();

// 使用静态变量帮助解决资源的分配和释放
// 肯定不能使用栈上的对象,不然会销毁
// 如果使用堆上的对象,在getInstance()方法中new出来,那就涉及到资源释放问题
// 析构函数是private的,外部是无法直接释放的
// 静态变量在程序中属于全局区,但声明了private后可见区域只在类内
// 所以可以让这个实例随着程序的产生而产生,随着程序的灭亡而灭亡
static Singleton* This;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Singleton.cpp

Singleton* Singleton::This = nullptr; //静态变量需要显式声明


const Singleton* Singleton::getInstance()
{
//这里只是简化了,还需要考虑多线程的情况
if (!This)
{
This = new Singleton;
}
return This;
}

Singleton::Singleton()
{
}

Singleton::~Singleton()
{
}
1
2
3
4
5
6
7
8
int main()
{
Singleton::getInstance()->DoSomething();

Singleton::getInstance()->DoSomething();

return 0;
}

  

  上面的单例模式实现,程序开始时全局实例Singleton* Singleton::This为空,只有我们主动调用Singleton::getInstance()->DoSomething()方法时才会产生这个对象的实例。我们也可以采用饿汉的方式,程序启动时就创建实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Singleton.cpp

Singleton* Singleton::This = new Singleton(); //这里直接new

const Singleton* Singleton::getInstance()
{
//这里只是简化了,还需要考虑多线程的情况
if (!This)
{
This = new Singleton;
}
return This;
}

Singleton::Singleton()
{
}

Singleton::~Singleton()
{
}

  

观察者模式

  在观察者模式中,观察者需要直接订阅目标事件;在目标发出内容改变的事件后,直接接收事件并作出相应;对象通常是一对多关系。常见于各种MVC的框架中,Model的变化通知各种类型的View时几乎都存在这种模式。

  观察者模式的实现思路:把问题的职责解耦合,将Observable和Observer抽象开,分清抽象和实体。

1
2
3
4
5
6
7
8
9
10
11
//观察者类

class Observer
{
public:
Observer() { ; }
virtual ~Observer() { ; }

// 当被观察对象发生变化时,通知被观察者调用这个方法
virtual void Update(void* pArg) = 0;
};

用list列表来存储被观察清单。

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
//被观察对象

class Observer;

class Observerable
{
public:
Observerable();
virtual ~Observerable();

// 注册观察者(加入被观察列表)
void Attach(Observer* pOb);
// 反注册观察者
void Detach(Observer* pOb);

int GetObseverCount() const
{
return _Obs.size();
}

void DetachAll() //清理所有订阅者
{
_Obs.clear();
}

virtual void GetSomeNews(string str)
{
SetChange(str);
}
protected:
void SetChange(string news); // 有变化,需要通知

private:
// 通知观察者
void Notify(void* pArg);

private:
bool _bChange;
list<Observer*> _Obs; //观察对象列表
};


// 注册观察者
void Observerable::Attach(Observer* pOb)
{
if (pOb == NULL)
{
return;
}

// 看看当前列表中是否有这个观察者
auto it = _Obs.begin();
for (; it != _Obs.end(); it++)
{
if (*it == pOb)
{
return;
}
}

_Obs.push_back(pOb);
}

// 反注册观察者
void Observerable::Detach(Observer* pOb)
{
if ((pOb == NULL) || (_Obs.empty() == true))
{
return;
}

_Obs.remove(pOb);
}

void Observerable::SetChange(string news)
{
_bChange = true;

Notify( ( (void*)news.c_str() ));
}


void Observerable::Notify(void* pArg)
{
if (_bChange == false)
{
return;
}

// 看看当前列表中是否有这个观察者
auto it = _Obs.begin();
for (; it != _Obs.end(); it++)
{
(*it)->Update(pArg);
}

_bChange = 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//main

//被观察对象
class News : public Observerable
{
public:
virtual void GetSomeNews(string str)
{
SetChange("News: " + str);
}
};

//两个观察者
class User1:public Observer
{
public:
virtual void Update(void* pArg)
{
cout << "User1 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
}
};
class User2 :public Observer
{
public:
virtual void Update(void* pArg)
{
cout << "User2 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
}
};

int main()
{
User1 u1;
User2 u2;

News n1;
n1.GetSomeNews("t0"); //此时没人订阅,什么事情都不会发生

//订阅
n1.Attach(&u1);
n1.Attach(&u2);
n1.GetSomeNews("t1");

n1.Detach(&u2);
n1.GetSomeNews("t2");

return 0;
}

  观察者模式帮助我们把职责关系梳理清晰了,我们如果要增加一个新的观察者,直接继承一个Observer类,实现一下消息更新的虚方法即可。

适配器(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
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
//适配器模式
//场景:
// 已经有一个矩形处理类LegacyRectangle,可以画一个矩形
// 此时收到需求,在画矩形之前需要额外输入一些别的东西,原有的LegacyRectangle类不能满足需求
//


//原始的矩形处理类
class LegacyRectangle
{
public:
LegacyRectangle(double x1, double y1, double x2, double y2)
{
_x1 = x1;
_y1 = y1;
_x2 = x2;
_y2 = y2;
}

void LegacyDraw()
{
cout << "LegacyRectangle:: LegacyDraw()" << _x1 << " " << _y1 << " " << _x2 << " " << _y2 << endl;
}

private:
double _x1;
double _y1;
double _x2;
double _y2;
};



// 创建一个抽象类和外部对接,让外部去调用这个接口
class Rectangle
{
public:
virtual void Draw(string str) = 0;
};


//创建内部接口,来实现对原始LegacyRectangle代码的复用
//有两种方式:

// 第一种适配的方式:使用多重继承,把原始的类一并继承
class RectangleAdapter: public Rectangle, public LegacyRectangle
{
public:
RectangleAdapter(double x, double y, double w, double h) :
LegacyRectangle(x, y, x + w, y + h)
{
cout << "RectangleAdapter(int x, int y, int w, int h)" << endl;
}

virtual void Draw(string str)
{
cout << "RectangleAdapter::Draw()" << endl;
LegacyDraw(); //实际使用的还是原始的方法
}
};

// 第二种适配的方式:组合方式的Adapter,把原始的类当作成员变量
// 这种方式更常见,因为可以避免多重继承方式的强耦合性
class RectangleAdapter2 :public Rectangle
{
public:
RectangleAdapter2(double x, double y, double w, double h) :
_lRect(x, y, x + w, y + h)
{
cout << "RectangleAdapter2(int x, int y, int w, int h)" << endl;
}

virtual void Draw(string str)
{
cout << "RectangleAdapter2::Draw()" << endl;
_lRect.LegacyDraw();
}
private:
LegacyRectangle _lRect;
};

int main()
{
double x = 20.0, y = 50.0, w = 300.0, h = 200.0;
//实际创建的是适配器对象,但接口调用用的是Rectangle接口类
RectangleAdapter ra(x, y, w, h);
Rectangle* pR = &ra;
pR->Draw("Testing Adapter");

cout << endl;

RectangleAdapter2 ra2(x, y, w, h);
Rectangle* pR2 = &ra2;
pR2->Draw("Testing2 Adapter");

return 0;
}