Linux C/C++服务器
创建型设计模式
学好设计模式需要对业务的稳定点和变化点有深刻的认识:业务的哪部分为稳定点,哪部分为变化点,从而进行合理的抽象,慎用设计模式,除非有明确的思路设计模式更好的能解决此类问题;
学好设计模式的意义:
1.读公司代码或开源项目比较容易;
2.自己写新的项目或开源代码使用设计模式,使代码更易扩展,增强健壮性、可读性,降低耦合
设计模式的基础
设计模式怎么来的? 满足设计原则后,慢慢迭代出来的
设计模式解决了什么问题?修改少量代码(不修改已有代码,在原有代码上扩展),就可以适应需求的变化 ;
比喻:整洁的房间,好动的猫,怎么保证房间的整洁?把猫关在一个笼子里
面向对象的思想
- 封装:隐藏实现细节,实现模块化
- 继承:无需修改原有类的情况下通过继承实现对功能的扩展
- 多态:静态多态(函数重载)、动态多态(虚函数重写)
动态多态
许多设计模式都会使用动态的多态,也叫做“晚绑定”
Base *p = new Subject();//如果Base内有virtual虚函数,此时就是晚绑定,p指向Subject的对象,如果没有虚函数,那么就是早绑定,Subject会被强制转换为Base类型
p->func2(); //此时调用Subject对象中的func2函数
设计原则
- 依赖倒置:使用者不应该依赖接口的具体实现,而仅应该依赖具体的接口
- 开闭原则:对扩展开放,对修改关闭
- 面向接口:和依赖导致类似
- 封装变化点:封装、多态
- 单一职责:封装
- 里氏替换:多态
- 接口隔离:
- 组合由于继承:
- 最小知道原则:使用者只要知道几个简单的使用接口就行了
模板方法
稳定点:不改变算法的骨架;变化点:子流程需要变化;开闭原则、里氏替换
需求:某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代更新表演流程;
template1使用普通的类构造方法,使用_type和if来判断来进行迭代的
随着迭代的增加,show0、show1...接口中的代码会不断的增加,当我们想知道某次迭代,修改了哪些功能的时候是比较困难的;而且每次迭代更新都要修改原有的类代码非常的不稳定
模板方法示例
符合设计模式的代码,迭代时只需通过多态继承基类即可,并且通过private与protected来作访问限制,使代码非常的稳定
#include <iostream>
using namespace std;
// 开闭
class ZooShow {
public:
void Show() {
// 如果子表演流程没有超时的话,进行一个中场游戏环节;如果超时,直接进入下一个子表演流程
if (Show0())
PlayGame();
Show1();
Show2();
Show3();
}
private:
void PlayGame() {
cout << "after Show0, then play game" << endl;
}
bool expired;
// 对其他用户关闭,但是子类开放的
protected:
virtual bool Show0() {
cout << "show0" << endl;
if (! expired) {
return true;
}
return false;
}
virtual void Show2() {
cout << "show2" << endl;
}
virtual void Show1() {
}
virtual void Show3() {
}
};
// 框架
// 模板方法模式
class ZooShowEx10 : public ZooShow {
protected:
virtual void Show0() {
if (! expired) {
return true;
}
return false;
}
}
class ZooShowEx1 : public ZooShow {
protected:
virtual bool Show0() {
cout << "ZooShowEx1 show0" << endl;
if (! expired) { // 里氏替换
return true;
}
return false;
}
virtual void Show2(){
cout << "show3" << endl;
}
};
class ZooShowEx2 : public ZooShow {
protected:
virtual void Show1(){
cout << "show1" << endl;
}
virtual void Show2(){
cout << "show3" << endl;
}
};
class ZooShowEx3 : public ZooShow {
protected:
virtual void Show1(){
cout << "show1" << endl;
}
virtual void Show3(){
cout << "show3" << endl;
}
virtual void Show4() {
//
}
};
/*
*/
int main () {
ZooShow *zs = new ZooShowEx10; // 晚绑定还是早绑定
// ZooShow *zs1 = new ZooShowEx1;
// ZooShow *zs2 = new ZooShowEx2;
zs->Show();
return 0;
}
观察者模式
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新
稳定点:“一”对“多”的依赖关系“一”变化“多”跟着变化;变化点:“多”增加,“多”减少
需求:气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到多个不同的显示终端;
observer1为不使用设计模式时的代码,DataCenter类不稳定,每次增加和减少显示终端都会重新修改其中的代码
观察者模式示例
通常使用Attach()、Detach()、Notify()、std::list<IDisplay*> obs进行抽象
增加新的显示模块只需新增显示类DisplayC:public IDisplay,然后attach,notify就可使用,不需要修改之前已有代码
#include <list>
#include <algorithm>
using namespace std;
//
class IDisplay {
public:
virtual void Show(float temperature) = 0;
virtual ~IDisplay() {}
};
class DisplayA : public IDisplay {
public:
virtual void Show(float temperature) {
cout << "DisplayA Show" << endl;
}
private:
void jianyi();
};
class DisplayB : public IDisplay{
public:
virtual void Show(float temperature) {
cout << "DisplayB Show" << endl;
}
};
class WeatherData {
};
// 应对稳定点,抽象
// 应对变化点,扩展(继承和组合)
class DataCenter {
public:
void Attach(IDisplay * ob) {
//
}
void Detach(IDisplay * ob) {
//
}
void Notify() {
float temper = CalcTemperature();
for (auto iter : obs) {
iter.Show(temper);
}
}
// 接口隔离
private:
WeatherData * GetWeatherData();
float CalcTemperature() {
WeatherData * data = GetWeatherData();
// ...
float temper/* = */;
return temper;
}
std::list<IDisplay*> obs; //基类列表,多态
};
int main() {
// 单例模式
DataCenter *center = new DataCenter;
// ... 某个模块
IDisplay *da = new DisplayA();
center->Attach(da);
// ...
IDisplay *db = new DisplayB();
center->Attach(db);
center->Notify();
//-----
center->Detach(db);
center->Notify();
return 0;
}
策略模式
定义一系列算法,把他们一个个封装起来,并且使它们可相互替换,该模式使得算法可独立于使用它的客户程序而变化
解决了什么问题?消除代码中的if else;稳定点:客户程序与算法的调用关系,变化点:算法变化
需求:某个商场节假日有固定的促销活动(稳定点),为了加大促销力度,现提升国庆节促销活动规格(变化点)
strategy1为不使用设计模式代码
Promotion类不稳定
strategy2为使用策略模式代码
接口隔离:依赖注入 通过ProStategy *s类依赖,注入到Promotion类中,未来任何改动都不会修改Promotion类中的代码,只需修改注入类(ProStategy *s)的指针指向即可