概述

1、设计模式的分类

总体来说设计模式分为三大类: 1、创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 2、结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 3、行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 4、其实还有两类:并发型模式和线程池模式。

1、设计原则

1.1、依赖原则

1、高层模块不应该依赖底层实现 2、抽象不应该依赖具体实现,实现应该依赖具体实现

1.2、开放封闭

1、一个类应该对(组合、继承开发),应该对修改闭合

1.3、面向接口

1、不要将某个变量型设计成特定类,而是声明成接口。 2、客户端不需要知道具体类型,只需要知道具体接口

1.4、封装变化点

将稳定点和变化点分离,扩展修改变化点,让稳定点和变化点的实现分离

1.5、单一职责

一个类应该仅有一个引起变化的原因

1.6、里氏替换

子类必须能够替换掉他的父类型,主要出现在子类覆盖父类实现,原来使用父类型程序可能出现错误,覆盖了父类型方法却没有实现父类职责

1.7、接口隔离

不应该强迫客户依赖于他们不用的接口

1.8、组合优于继承

继承耦合性高,组合耦合性低

设计模式遵循以上原则衍生出来的

2、模板方法

2.1、定义

定义一个操作类的框架,而将一些步骤延迟到子类中,使得子类可以改变这个框架的具体实现,但是主体部分还是由框架限制

2.2、背景

某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代 更新表演流程;

2.3、要点

最常用的设计模式,子类可以复写父类子流程,使父类的骨架流程丰富;反向控制流程的典型应用;父类 protected 保护子类需要复写的子流程;这样子类的子流程只能父类来调用

2.4、没使用设计模式实现

从代码中可以看出,用户只能调用Show方法,而且后续show1、show2、show3会越来越大

#include <iostream>
usingnamespace std;

#if 0
classZooShow{
public:
void Show0() {
        cout <<"show0"<< endl;
}
void Show2() {
        cout <<"show2"<< endl;
}
};

classZooShowEx{
public:
void Show1() {
        cout <<"show1"<< endl;
}
void Show3() {
        cout <<"show3"<< endl;
}
};

// 不满足单一职责 , 开 扩展 修改闭原则
// 动物园固定流程,迭代创新
// 稳定和变化   一定的方向上变化
#else if 2
classZooShow{
public:
ZooShow(int type =1): _type(type){}

public:
void Show() {
if(Show0())
PlayGame();// 里氏替换
Show1();
Show2();
Show3();
}

// 接口隔离 不要让用户去选择它们不需要的接口
private:
void PlayGame() {
        cout <<"after Show0, then play game"<< endl;
}

private:
bool Show0() {
        cout << _type <<" show0"<< endl;
returntrue;
}

void Show1() {
if(_type ==1){
            cout << _type <<" Show1"<< endl;
}elseif(_type ==2){
            cout << _type <<" Show1"<< endl;
}elseif(_type ==3){

}
}

voidShow2(){
if(_type ==20){

}
        cout <<"base Show2"<< endl;
}

void Show3() {
if(_type ==1){
            cout << _type <<" Show1"<< endl;
}elseif(_type ==2){
            cout << _type <<" Show1"<< endl;
}
}
private:
int _type;
};

#endif

int main () {
#if 0
ZooShow*zs =newZooShow;
ZooShowEx*zs1 =newZooShowEx;
    zs->Show0();
    zs1->Show1();
    zs->Show2();
    zs1->Show3();
#else if 2
ZooShow*zs =newZooShow(1);
    zs->Show();
#endif
return0;
}

2.5、使用设计模式实现

遵循上面所说,父类控制主体结构,通过protected保护下面的方法,只有子类可以重写,用户不能调用,所以,后续扩展show1、show2、show3就是特别方便

#include <iostream>
usingnamespace std;

// 不满足开闭原则    对扩展开放   继承(虚函数覆盖)
// 扩展功能:继承 (虚函数覆盖) 组合
classZooShow{
public:
void Show() {
if(Show0())
PlayGame();
Show1();
Show2();
Show3();
}

private:
void PlayGame() {
        cout <<"after Show0, then play game"<< endl;
}

protected:
virtual bool Show0(){
        cout <<"show0"<< endl;
returntrue;
}
virtual void Show2(){
        cout <<"show2"<< endl;
}
virtual void Show1() {

}
virtual void Show3() {

}
};

classZooShowEx1:publicZooShow{
protected:
virtual bool Show0(){
        cout <<"show1"<< endl;
returntrue;
}
virtual void Show2(){
        cout <<"show3"<< endl;
}
};

classZooShowEx2:publicZooShow{
protected:
virtual void Show1(){
        cout <<"show1"<< endl;
}
virtual void Show2(){
        cout <<"show3"<< endl;
}
};

classZooShowEx3:publicZooShow{
protected:
virtual void Show1(){
        cout <<"show1"<< endl;
}
virtual void Show3(){
        cout <<"show3"<< endl;
}
virtual void Show4() {
//
}
};
/*
*/
int main () {
ZooShow*zs =newZooShowEx3;
// ZooShow *zs1 = new ZooShowEx1;
// ZooShow *zs2 = new ZooShowEx2;
    zs->Show();
return0;
}

3、观察者模式

3.1、定义

定义一组一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发送改变时候所依赖他的对象都得到通知和更新

3.2、背景

气象站发布数据给数据中,数据中心通过处理,将气象站的数据更新到多个终端设备上

3.3、要点

观察者模式使得我们可以独立地改变目标与观察者,从而使二者之间的关系松耦合; 观察者自己决定是否订阅通知,目标对象并不关注谁订阅了; 观察者不要依赖通知顺序,目标对象也不知道通知顺序; 常用在基于事件的ui框架中,也是 MVC 的组成部分; 常用在分布式系统中、actor框架中;

3.4、没使用设计模式实现

从代码中可以看出,没添加一个终端设备,都会调用数据中心的接口,然后进行显示,显然与我们的初衷违背了,我们初衷是,气象中心将数据给到,数据中心进行计算,计算完之后下发给所有的终端,在这个过程中不关心当前有多少终端设备,也不关心终端设备收到这个数据做什么具体的定制化操作。

class DisplayA{
public:
void Show(float temperature);
};

classDisplayB{
public:
void Show(float temperature);
};

classDisplayC{
public:
void Show(float temperature);
}

classWeatherData{
};

classDataCenter{
public:
float CalcTemperature() {
WeatherData* data =GetWeatherData();
// ...
float temper/* = */;
return temper;
}
private:
WeatherData * GetWeatherData();// 不同的方式
};

// 订阅发布
int main() {
DataCenter*center =newDataCenter;
DisplayA*da =newDisplayA;
DisplayB*db =newDisplayB;
DisplayC*dc =newDisplayC;
float temper = center->CalcTemperature();
    da->Show(temper);
    db->Show(temper);
    dc->Show(temper);
return0;
}
// 终端变化(增加和删除)   数据中心 不应该受终端变化的影响

3.5、使用设计模式实现

通过一个抽象类,规定了所有终端设备必须实现这个类,每个子类可以根据自己需要做一些定制化的开发,数据中心通过遍历终端容器进行数据下发。

#include <vector>

//
classIDisplay{
public:
virtual void Show(float temperature) =0;
virtual~IDisplay(){}
};

classDisplayA:publicIDisplay{
public:
virtual void Show(float temperature);
private:
void jianyi();
};

classDisplayB:publicIDisplay{
public:
virtual void Show(float temperature);
};

classDisplayC:publicIDisplay{
public:
virtual void Show(float temperature);
};

classWeatherData{
};

classDataCenter{
public:
void Attach(IDisplay * ob);
void Detach(IDisplay * ob);
void Notify() {
float temper =CalcTemperature();
for(auto iter = obs.begin(); iter != obs.end(); iter++){
(*iter)->Show(temper);
}
}

// 接口隔离
private:
virtual WeatherData * GetWeatherData();

virtual float CalcTemperature() {
WeatherData* data =GetWeatherData();
// ...
float temper/* = */;
return temper;
}
    std::vector<IDisplay*> obs;
};

int main() {
DataCenter*center =newDataCenter;
IDisplay*da =newDisplayA();
IDisplay*db =newDisplayB();
IDisplay*dc =newDisplayC();
    center->Attach(da);
    center->Attach(db);
    center->Attach(dc);



    center->Notify();

//-----
    center->Detach(db);
    center->Notify();
return0;
}

4、策略模式

4.1、定义

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用 它的客户程序而变化。 ——《设计模式》 GoF

4.2、背景

某商场节假日有固定促销活动,为了加大促销力度,现提升国庆节促销活动规格;

4.3、要点

策略模式提供了一系列可重用的算法,从而可以使得类型在运⾏时方便地根据需要在各个算法之间 进行切换; 策略模式消除了条件判断语句;也就是在解耦合

4.4、没使用设计模式实现

节日的增加会让这个函数类的if else越来越多

enum VacationEnum{
    VAC_Spring,
    VAC_QiXi,
    VAC_Wuyi,
    VAC_GuoQing,
    VAC_ShengDan,
};


// 稳定点  变化点
// 如果一个 只有稳定点  需不需要设计模式
// 如果 全是变化点  怎么办?   c++  游戏开发  脚本语言
classPromotion{
VacationEnum vac;
public:
double CalcPromotion(){
if(vac == VAC_Spring {
// 春节
}
elseif(vac == VAC_QiXi){
// 七夕
}
elseif(vac == VAC_Wuyi){
// 五一
}
elseif(vac == VAC_GuoQing){
// 国庆
}
elseif(vac == VAC_ShengDan){

}
}

};

4.5、使用设计模式实现

class Context{

};

classProStategy{
public:
virtual double CalcPro(const Context &ctx) =0;
virtual~ProStategy();
};
// cpp
classVAC_Spring:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_QiXi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
classVAC_QiXi1:public VAC_QiXi {
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_Wuyi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_GuoQing:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

classVAC_Shengdan:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

classPromotion{
public:
Promotion(ProStategy*sss):s(sss){}
~Promotion(){}
double CalcPromotion(const Context &ctx){
return s->CalcPro(ctx);
}
private:
ProStategy*s;
};

int main () {
Context ctx;
ProStategy*s =newVAC_QiXi1();
Promotion*p =newPromotion(s);
    p->CalcPromotion(ctx);
return0;
}

4.6、继续优化

上面写法用户使用的时候,暴露了太多创建过程,这种写法只需要传入对应枚举,实现过程在类中

#include <iostream>
enumRA{
    VAC_Spring,
    VAC_QiXi,
    VAC_QiXi1,
    VAC_Wuyi,
    VAC_GuoQing,
    VAC_Shengdan
};

classContext{

};

classProStategy{
public:
virtual double CalcPro(const Context &ctx) =0;
virtual~ProStategy();
};
// cpp
classVAC_Spring:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_QiXi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
classVAC_QiXi1:public VAC_QiXi {
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_Wuyi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_GuoQing:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

classVAC_Shengdan:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

classPromotion{
public:
Promotion(enum RA ra){
if(ra == RA::VAC_GuoQing){
            s =newVAC_GuoQing();
}elseif(ra == RA::VAC_QiXi){
            s =newVAC_QiXi();
}
}
~Promotion(){}
double CalcPromotion(const Context &ctx){
return s->CalcPro(ctx);
}
private:
ProStategy*s;
};

int main () {
Context ctx;
Promotion*p =newPromotion(VAC_Spring);
    p->CalcPromotion(ctx);
return0;
}

4.7、优化

使用模板的方式更简单

#include <iostream>

classContext{

};

classProStategy{
public:
virtual double CalcPro(const Context &ctx) =0;
virtual~ProStategy();
};
// cpp
classVAC_Spring:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_QiXi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
classVAC_QiXi1:public VAC_QiXi {
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_Wuyi:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};
// cpp
classVAC_GuoQing:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

classVAC_Shengdan:publicProStategy{
public:
virtual double CalcPro(const Context &ctx){}
};

template<classRA>
classPromotion{
public:
Promotion(){}
~Promotion(){}
double CalcPromotion(const Context &ctx){
return m_ra.CalcPro(ctx);
}
private:
    RA m_ra;
};

int main () {
Context ctx;
Promotion<VAC_QiXi> p;
    p.CalcPromotion(ctx);
return0;
}

5、单例模式

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

5.1、版本一

版本一存在的问题: 1、没有考虑多线程情况下,会出现多次创建 2、内存泄漏,我们的析构函数在private里面不会被调用

class Singletion{
public:
static Singletion *GetInstance(){
if(_instance ==nullptr){
            _instance =newSingletion();
}
return _instance;
}
private:
Singletion(){}
~Singletion(){}
Singletion(constSingletion&clone){}
Singletion&operator=(constSingletion&){}
staticSingletion* _instance;
};
Singletion*Singletion::_instance =nullptr;

5.2、版本二

版本二存在问题: 虽然表面上解决了多线程出现多次创建的问题,和内存泄漏的问题,但是实际上隐藏一个bug new会做三件事:1、分配内存,2、调用构造函数,3、返回指针,但是cpu在执行的时候可能会优化执行过程,导致做这三件事的顺序发生改变,所以就会存在一个cpu reorder操作。

#include <mutex>
classSingleton{// 懒汉模式 lazy load
public:
static Singleton * GetInstance() {
if(_instance ==nullptr){
std::lock_guard<std::mutex> lock(_mutex);// 3.2
if(_instance ==nullptr){
            _instance =newSingleton();
atexit(Destructor);
}
}
return _instance;
}
private:
static void Destructor() {
if(nullptr!= _instance){
delete _instance;
            _instance =nullptr;
}
}
Singleton(){}//构造
Singleton(constSingleton&cpy){}//拷⻉构造
Singleton&operator=(constSingleton&){}
staticSingleton* _instance;
static std::mutex _mutex;
};
Singleton*Singleton::_instance =nullptr;//静态成员需要初始化
std::mutex Singleton::_mutex; //互斥锁初始化

5.3、版本三

使用内存屏障确实可以解决这个问题,但是实现起来太复杂 g++ Singleton.cpp -o singleton -std=c++11

#include <mutex>
#include <atomic>
classSingleton{
public:
static Singleton * GetInstance() {
Singleton* tmp = _instance.load(std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_acquire);//获取内存屏障
if(tmp ==nullptr){
std::lock_guard<std::mutex> lock(_mutex);
            tmp = _instance.load(std::memory_order_relaxed);
if(tmp ==nullptr){
                tmp =newSingleton;
                std::atomic_thread_fence(std::memory_order_release);//释放内存屏障
                _instance.store(tmp, std::memory_order_relaxed);
atexit(Destructor);
}
}
return tmp;
}

private:
static void Destructor() {
Singleton* tmp = _instance.load(std::memory_order_relaxed);
if(nullptr!= tmp){
delete tmp;
}
}

Singleton(){}
Singleton(constSingleton&){}
Singleton&operator=(constSingleton&){}
static std::atomic<Singleton*> _instance;
static std::mutex _mutex;
};
std::atomic<Singleton*>Singleton::_instance;//静态成员需要初始化
std::mutex Singleton::_mutex;//互斥锁初始化
// g++ Singleton.cpp -o singleton -std=c++11

5.4、版本四

c++11 magic static 特性:如果当变量在初始化的时候,并发同时进⼊声明语句,并发线程将会阻塞等待初始化结束。

  1. 1. 利⽤静态局部变量特性,延迟加载;
  2. 2. 利⽤静态局部变量特性,系统⾃动回收内存,⾃动调⽤析构函数;
  3. 3. 静态局部变量初始化时,没有 new 操作带来的cpu指令reorder操作;
  4. 4. c++11 静态局部变量初始化时,具备线程安全
class Singleton
{
public:
static Singleton& GetInstance() {
staticSingleton instance;
return instance;
}
private:
Singleton(){}
~Singleton(){}
Singleton(constSingleton&){}
Singleton&operator=(constSingleton&){}
};

5.5、版本五

项目中可以将Singleton写成一个模板父类,需要实现单例类继承他。 1、为什么子类中要把父类写成他的友元,因为子类是在父类中的GetInstance中构建出来的,需要调用子类的构造函数,而子类的构造函数又是private,所以需要将父类写成子类的友元。

template<typename T>
classSingleton{
public:
static T& GetInstance(){
static T instance;
return instance;
}
protected:
Singleton(){}
virtual~Singleton(){}
Singleton(constSingleton&){}
Singleton&operator=(constSingleton&){}
}

classDesignPattern:publicSingleton<DesignPattern>{
friendclassSingleton<DesignPattern>;
public:
~DesignPattern(){}
private:
DesignPattern(){}
DesignPattern(constDesignPattern&){}
DesignPattern&operator=(constDesignPattern&){}
}

6、工厂方法

定义一个用于创建接口,让子类决定实例化哪一个类Factory Method使得一个类实例化延迟到子类

背景

实现一个导出数据的接口,让客户选择数据的导出方式;

要点

解决创建过程比较复杂,希望对外隐藏这些细节的场景; 比如连接池、线程池 隐藏对象真实类型; 对象创建会有很多参数来决定如何创建; 创建对象有复杂的依赖关系;

6.1、版本一

1、遵循设计模式原则,面向接口编程,将导出数据封装成一个接口类,其他的都继承他,通过if进行判断确定new哪个子类

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
classIExport{
public:
virtual bool Export(const std::string &data) =0;
virtual~IExport(){}
};

classExportXml:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportJson:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};
// csv
classExportTxt:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

// class ExportCSV : public IExport {
// public:
//     virtual bool Export(const std::string &data) {
//         return true;
//     }
// };

// =====1
int main() {
    std::string choose/* = */;
if(choose =="txt"){
/***/
IExport*e =newExportTxt();
/***/
        e->Export("hello world");
}elseif(choose =="json"){
/***/
IExport*e =newExportJson();
/***/
        e->Export("hello world");
}elseif(choose =="xml"){
IExport*e =newExportXml();
        e->Export("hello world");
}elseif(choose =="csv"){
IExport*e =newExportXml();
        e->Export("hello world");
}
}

6.2、版本二

优化了创建子类部分,实现了一个简单工厂模式

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
classIExport{
public:
virtual bool Export(const std::string &data) =0;
virtual~IExport(){}
};

classExportXml:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportJson:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportTxt:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classIExportFactory{
public:
virtual IExport * NewExport(/* ... */) =0;
};

classExportXmlFactory:publicIExportFactory{
public:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportXml;
// 可能之后有什么操作
return temp;
}
};

classExportJsonFactory:publicIExportFactory{
public:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportJson;
// 可能之后有什么操作
return temp;
}
};

classExportTxtFactory:publicIExportFactory{
public:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportTxt;
// 可能之后有什么操作
return temp;
}
};

classExportData{
public:
ExportData(IExportFactory*factory): _factory(factory){}
~ExportData(){
if(_factory){
delete _factory;
            _factory =nullptr;
}
}
bool Export(const std::string &data) {// 稳定的流程 往基类放 
IExport* e = _factory->NewExport();
        e->Export(data);
}
private:
IExportFactory*_factory;
};

int main() {
ExportData ed(new ExportTxtFactory);
    ed.Export("hello world");
return0;
}

6.3、版本三

将子类创建细节全部隐藏起来,用户知道的越少越好。

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
classIExport{
public:
virtual bool Export(const std::string &data) =0;
virtual~IExport(){}
};

classExportXml:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportJson:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportTxt:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportCSV:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classIExportFactory{
public:
IExportFactory(){
        _export =nullptr;
}
virtual~IExportFactory(){
if(_export){
delete _export;
            _export =nullptr;
}
}
bool Export(const std::string &data) {
if(_export ==nullptr){
            _export =NewExport();
}
return _export->Export(data);
}
protected:
virtual IExport * NewExport(/* ... */) =0;
private:
IExport* _export;
};

classExportXmlFactory:publicIExportFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportXml();
// 可能之后有什么操作
return temp;
}
};
classExportJsonFactory:publicIExportFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportJson;
// 可能之后有什么操作
return temp;
}
};
classExportTxtFactory:publicIExportFactory{
protected:
IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportTxt;
// 可能之后有什么操作
return temp;
}
};

classExportCSVFactory:publicIExportFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportCSV;
// 可能之后有什么操作
return temp;
}
};

int main () {
IExportFactory*factory =newExportTxtFactory();
    factory->Export("hello world");
return0;
}

6.4、抽象工厂

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
classIExport{
public:
virtual bool Export(const std::string &data) =0;
virtual~IExport(){}
};

classExportXml:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportJson:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportTxt:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classExportCSV:publicIExport{
public:
virtual bool Export(const std::string &data) {
returntrue;
}
};

classIImport{
public:
virtual bool Import(const std::string &data) =0;
virtual~IImport(){}
};

classImportXml:publicIImport{
public:
virtual bool Import(const std::string &data) {
returntrue;
}
};

classImportJson:publicIImport{
public:
virtual bool Import(const std::string &data) {
returntrue;
}
};

classImportTxt:publicIImport{
public:
virtual bool Import(const std::string &data) {
returntrue;
}
};

// 对于初学者: 知道扩展代码
// 5年
classImportCSV:publicIImport{
public:
virtual bool Import(const std::string &data) {
// ....
returntrue;
}
};

classIDataApiFactory{
public:
IDataApiFactory(){
        _export =nullptr;
        _import =nullptr;
}
virtual~IDataApiFactory(){
if(_export){
delete _export;
            _export =nullptr;
}
if(_import){
delete _import;
            _import =nullptr;
}
}
bool Export(const std::string &data) {
if(_export ==nullptr){
            _export =NewExport();
}
return _export->Export(data);
}
bool Import(const std::string &data) {
if(_import ==nullptr){
            _import =NewImport();
}
return _import->Import(data);
}
protected:
virtual IExport * NewExport(/* ... */) =0;
virtual IImport * NewImport(/* ... */) =0;
private:
IExport*_export;
IImport*_import;
};

classXmlApiFactory:publicIDataApiFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportXml;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport* temp =newImportXml;
// 可能之后有什么操作
return temp;
}
};

classJsonApiFactory:publicIDataApiFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportJson;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport* temp =newImportJson;
// 可能之后有什么操作
return temp;
}
};
classTxtApiFactory:publicIDataApiFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportTxt;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport* temp =newImportTxt;
// 可能之后有什么操作
return temp;
}
};

classCSVApiFactory:publicIDataApiFactory{
protected:
virtual IExport * NewExport(/* ... */) {
// 可能有其它操作,或者许多参数
IExport* temp =newExportCSV;
// 可能之后有什么操作
return temp;
}
virtual IImport * NewImport(/* ... */) {
// 可能有其它操作,或者许多参数
IImport* temp =newImportCSV;
// 可能之后有什么操作
return temp;
}
};

// 相关性  依赖性    工作当中
int main () {
IDataApiFactory*factory =newCSVApiFactory();
    factory->Import("hello world");
    factory->Export("hello world");
return0;
}

7、适配器

7.1、定义

适配器模式是,将一个类的接口转化成另外一个客户希望的接口,使得原本接口不兼容不能一起工作的类,能够一起工作,它包含了类适配器和对象适配器。

7.2、背景

在STL中就用到了适配器模式。STL实现了一种数据结构,称为双端队列(deque),支持前后两段的插入与删除。STL实现栈和队列时,没有从头开始定义它们,而是直接使用双端队列实现的。这里双端队列就扮演了适配器的角色。队列用到了它的后端插入,前端删除。而栈用到了它的后端插入,后端删除。假设栈和队列都是一种顺序容器,有两种操作:压入和弹出。

7.3、实现

//双端队列  
classDeque
{
public:
void push_back(int x) { cout<<"Deque push_back"<<endl;}
void push_front(int x) { cout<<"Deque push_front"<<endl;}
void pop_back() { cout<<"Deque pop_back"<<endl;}
void pop_front() { cout<<"Deque pop_front"<<endl;}
};
//顺序容器  
classSequence
{
public:
virtual void push(int x) =0;
virtual void pop() =0;
};
//栈  
classStack:publicSequence
{
public:
void push(int x) { deque.push_back(x);}
void pop() { deque.pop_back();}
private:
Deque deque;//双端队列  
};
//队列  
classQueue:publicSequence
{
public:
void push(int x) { deque.push_back(x);}
void pop() { deque.pop_front();}
private:
Deque deque;//双端队列  
};

int main()  
{
Sequence*s1 =newStack();
Sequence*s2 =newQueue();
    s1->push(1); s1->pop();
    s2->push(1); s2->pop();
delete s1;delete s2;
return0;
}

8、建造者模式

8.1、定义

建造者模式是将一个复杂的对象构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

8.2、背景

建造小人,一共需建造6个部分,头部、身体、左右手、左右脚。与工厂模式不同,建造者模式是在导向者的控制下一步一步构造产品的。建造小人就是在控制下一步步构造出来的。创建者模式可以能更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

8.3、实现

class Builder
{
public:
virtual void BuildHead() {}
virtual void BuildBody() {}
virtual void BuildLeftArm(){}
virtual void BuildRightArm() {}
virtual void BuildLeftLeg() {}
virtual void BuildRightLeg() {}
};
//构造瘦人  
classThinBuilder:publicBuilder
{
public:
void BuildHead() { cout<<"build thin body"<<endl;}
void BuildBody() { cout<<"build thin head"<<endl;}
void BuildLeftArm() { cout<<"build thin leftarm"<<endl;}
void BuildRightArm() { cout<<"build thin rightarm"<<endl;}
void BuildLeftLeg() { cout<<"build thin leftleg"<<endl;}
void BuildRightLeg() { cout<<"build thin rightleg"<<endl;}
};
//构造胖人  
classFatBuilder:publicBuilder
{
public:
void BuildHead() { cout<<"build fat body"<<endl;}
void BuildBody() { cout<<"build fat head"<<endl;}
void BuildLeftArm() { cout<<"build fat leftarm"<<endl;}
void BuildRightArm() { cout<<"build fat rightarm"<<endl;}
void BuildLeftLeg() { cout<<"build fat leftleg"<<endl;}
void BuildRightLeg() { cout<<"build fat rightleg"<<endl;}
};
//构造的指挥官  
classDirector
{
private:
Builder*m_pBuilder;
public:
Director(Builder*builder){ m_pBuilder = builder;}
void Create(){
        m_pBuilder->BuildHead();
        m_pBuilder->BuildBody();
        m_pBuilder->BuildLeftArm();
        m_pBuilder->BuildRightArm();
        m_pBuilder->BuildLeftLeg();
        m_pBuilder->BuildRightLeg();
}
};

int main()  
{
FatBuilder thin;
Director director(&thin);
    director.Create();
return0;
}

9、代理模式

9.1、定义

为其他对象提供一种代理以控制对这个对象的访问。有四种常用的情况:(1)远程代理,(2)虚代理,(3)保护代理,(4)智能引用,主要介绍虚代理和智能引用两种情况。

9.2、背景

考虑一个可以在文档中嵌入图形对象的文档编辑器。有些图形对象的创建开销很大。但是打开文档必须很迅速,因此我们在打开文档时应避免一次性创建所有开销很大的对象。这里就可以运用代理模式,在打开文档时,并不打开图形对象,而是打开图形对象的代理以替代真实的图形。待到真正需要打开图形时,仍由代理负责打开。

9.2、虚代理实现

class Image
{
public:
Image(string name):m_imageName(name){}
virtual~Image(){}
virtual void Show() {}
protected:
    string m_imageName;
};
classBigImage:publicImage
{
public:
BigImage(string name):Image(name){}
~BigImage(){}
void Show() { cout<<"Show big image : "<<m_imageName<<endl;}
};
classBigImageProxy:publicImage
{
private:
BigImage*m_bigImage;
public:
BigImageProxy(string name):Image(name),m_bigImage(0){}
~BigImageProxy(){delete m_bigImage;}
void Show()   
    {
if(m_bigImage ==NULL)
            m_bigImage =newBigImage(m_imageName);
        m_bigImage->Show();
}
};

int main()  
{
Image*image =newBigImageProxy("proxy.jpg");//代理  
    image->Show();//需要时由代理负责打开  
delete image;
return0;
}

9.3、智能引用

template <typename T>
classsmart_ptr
{
public:
smart_ptr(T *p =0):pointee(p),count(newsize_t(1)){}//初始的计数值为1  
smart_ptr(const smart_ptr &rhs):pointee(rhs.pointee),count(rhs.count){++*count;}//拷贝构造函数,计数加1  
~smart_ptr(){decr_count();}//析构,计数减1,减到0时进行垃圾回收,即释放空间  
    smart_ptr&operator=(const smart_ptr& rhs)//重载赋值操作符  
{
//给自身赋值也对,因为如果自身赋值,计数器先减1,再加1,并未发生改变  
++*count;
decr_count();
        pointee = rhs.pointee;
        count = rhs.count;
return*this;
}
//重载箭头操作符和解引用操作符,未提供指针的检查  
    T *operator->(){return pointee;}
const T *operator->()const{return pointee;}
    T &operator*(){return*pointee;}
const T &operator*()const{return*pointee;}
size_t get_refcount() {return*count;}//获得引用计数器值  
private:
    T *pointee;//实际指针,被代理    
size_t*count;//引用计数器  
void decr_count() //计数器减1  
    {
if(--*count ==0)
{
delete pointee;
delete count;
}
}
};

10、桥接模式

10.1、定义

将抽象部分与它的实现部分分离,使它们都可以独立地变化。考虑装操作系统,有多种配置的计算机,同样也有多款操作系统。如何运用桥接模式呢?可以将操作系统和计算机分别抽象出来,让它们各自发展,减少它们的耦合度。当然了,两者之间有标准的接口。这样设计,不论是对于计算机,还是操作系统都是非常有利的

10.2、实现

//操作系统  
classOS
{
public:
virtual void InstallOS_Imp() {}
};
classWindowOS:public OS  
{
public:
void InstallOS_Imp() { cout<<"安装Window操作系统"<<endl;}
};
classLinuxOS:public OS  
{
public:
void InstallOS_Imp() { cout<<"安装Linux操作系统"<<endl;}
};
classUnixOS:public OS  
{
public:
void InstallOS_Imp() { cout<<"安装Unix操作系统"<<endl;}
};
//计算机  
classComputer
{
public:
virtual void InstallOS(OS *os) {}
};
classDellComputer:publicComputer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp();}
};
classAppleComputer:publicComputer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp();}
};
classHPComputer:publicComputer
{
public:
void InstallOS(OS *os) { os->InstallOS_Imp();}
};

int main()  
{
    OS *os1 =newWindowOS();
    OS *os2 =newLinuxOS();
Computer*computer1 =newAppleComputer();
    computer1->InstallOS(os1);
    computer1->InstallOS(os2);
}

11、装饰器模式

11.1、定义

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。有时我们希望给某个对象而不是整个类添加一些功能。比如有一个手机,允许你为手机添加特性,比如增加挂件、屏幕贴膜等。一种灵活的设计方式是,将手机嵌入到另一对象中,由这个对象完成特性的添加,我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。

11.2、实现

//公共抽象类  
classPhone
{
public:
Phone(){}
virtual~Phone(){}
virtual void ShowDecorate() {}
};

//具体的手机类  
classiPhone:publicPhone
{
private:
    string m_name;//手机名称  
public:
iPhone(string name):m_name(name){}
~iPhone(){}
void ShowDecorate() { cout<<m_name<<"的装饰"<<endl;}
};
//具体的手机类  
classNokiaPhone:publicPhone
{
private:
    string m_name;
public:
NokiaPhone(string name):m_name(name){}
~NokiaPhone(){}
void ShowDecorate() { cout<<m_name<<"的装饰"<<endl;}
};

//装饰类  
classDecoratorPhone:publicPhone
{
private:
Phone*m_phone;//要装饰的手机  
public:
DecoratorPhone(Phone*phone):m_phone(phone){}
virtual void ShowDecorate() { m_phone->ShowDecorate();}
};
//具体的装饰类  
classDecoratorPhoneA:publicDecoratorPhone
{
public:
DecoratorPhoneA(Phone*phone):DecoratorPhone(phone){}
void ShowDecorate() {DecoratorPhone::ShowDecorate();AddDecorate();}
private:
void AddDecorate() { cout<<"增加挂件"<<endl;}//增加的装饰  
};
//具体的装饰类  
classDecoratorPhoneB:publicDecoratorPhone
{
public:
DecoratorPhoneB(Phone*phone):DecoratorPhone(phone){}
void ShowDecorate() {DecoratorPhone::ShowDecorate();AddDecorate();}
private:
void AddDecorate() { cout<<"屏幕贴膜"<<endl;}//增加的装饰  
};


int main()  
{
Phone*iphone =newNokiaPhone("6300");
Phone*dpa =newDecoratorPhoneA(iphone);//装饰,增加挂件  
Phone*dpb =newDecoratorPhoneB(dpa);//装饰,屏幕贴膜  
    dpb->ShowDecorate();
delete dpa;
delete dpb;
delete iphone;
return0;
}

12、职责链模式

12.1、定义

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。其思想很简单,考虑员工要求加薪。公司的管理者一共有三级,总经理、总监、经理,如果一个员工要求加薪,应该向主管的经理申请,如果加薪的数量在经理的职权内,那么经理可以直接批准,否则将申请上交给总监。总监的处理方式也一样,总经理可以处理所有请求。这就是典型的职责链模式,请求的处理形成了一条链,直到有一个对象处理请求。

12.2、实现

//抽象管理者  
classManager
{
protected:
Manager*m_manager;
    string m_name;
public:
Manager(Manager*manager, string name):m_manager(manager),m_name(name){}
virtual void DealWithRequest(string name, int num)  {}
};
//经理  
classCommonManager:publicManager
{
public:
CommonManager(Manager*manager, string name):Manager(manager,name){}
void DealWithRequest(string name, int num)   
    {
if(num <500)//经理职权之内  
{
            cout<<"经理"<<m_name<<"批准"<<name<<"加薪"<<num<<"元"<<endl<<endl;
}
else
{
            cout<<"经理"<<m_name<<"无法处理,交由总监处理"<<endl;
            m_manager->DealWithRequest(name, num);
}
}
};
//总监  
classMajordomo:publicManager
{
public:
Majordomo(Manager*manager, string name):Manager(manager,name){}
void DealWithRequest(string name, int num)   
    {
if(num <1000)//总监职权之内  
{
            cout<<"总监"<<m_name<<"批准"<<name<<"加薪"<<num<<"元"<<endl<<endl;
}
else
{
            cout<<"总监"<<m_name<<"无法处理,交由总经理处理"<<endl;
            m_manager->DealWithRequest(name, num);
}
}
};
//总经理  
classGeneralManager:publicManager
{
public:
GeneralManager(Manager*manager, string name):Manager(manager,name){}
void DealWithRequest(string name, int num)  //总经理可以处理所有请求  
    {
        cout<<"总经理"<<m_name<<"批准"<<name<<"加薪"<<num<<"元"<<endl<<endl;
}
};

int main()  
{
Manager*general =newGeneralManager(NULL,"A");//设置上级,总经理没有上级  
Manager*majordomo =newMajordomo(general,"B");//设置上级  
Manager*common =newCommonManager(majordomo,"C");//设置上级  
    common->DealWithRequest("D",300);//员工D要求加薪  
    common->DealWithRequest("E",600);
    common->DealWithRequest("F",1000);
delete common;delete majordomo;delete general;
return0;
}

未完!!!