C++ 设计模式学习

文章目录

  • 1、设计原则
    • 1.1、依赖原则
    • 1.2、开放封闭
    • 1.3、面向接口
    • 1.4、封装变化点
    • 1.5、单一职责
    • 1.6、里氏替换
    • 1.7、接口隔离
    • 1.8、组合优于继承
  • 2、模板方法
    • 2.1、定义
    • 2.2、背景
    • 2.3、要点
    • 2.4、没使用设计模式实现
    • 2.5、使用设计模式实现
  • 3、观察者模式
    • 3.1、定义
    • 3.2、背景
    • 3.3、要点
    • 3.4、没使用设计模式实现
    • 3.5、使用设计模式实现
  • 4、策略模式
    • 4.1、定义
    • 4.2、背景
    • 4.3、要点
    • 4.4、没使用设计模式实现
  • 4.5、使用设计模式实现
  • 未完!!!

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 
using namespace std;

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

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

// 不满足单一职责 , 开 扩展 修改闭原则
// 动物园固定流程,迭代创新
// 稳定和变化   一定的方向上变化
#else if 2
class ZooShow {
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;
        return true;
    }

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

        }
    }

    void Show2() {
        if (_type == 20) {
            
        }
        cout << "base Show2" << endl;
    }

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

#endif

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

2.5、使用设计模式实现

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

#include 
using namespace std;

// 不满足开闭原则    对扩展开放   继承(虚函数覆盖)
// 扩展功能:继承 (虚函数覆盖) 组合
class ZooShow {
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;
        return true;
    }
    virtual void Show2(){
        cout << "show2" << endl;
    }
    virtual void Show1() {

    }
    virtual void Show3() {

    }
};

class ZooShowEx1 : public ZooShow {
protected:
    virtual bool Show0(){
        cout << "show1" << endl;
        return true;
    }
    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 ZooShowEx3;
    // ZooShow *zs1 = new ZooShowEx1;
    // ZooShow *zs2 = new ZooShowEx2;
    zs->Show();
    return 0;
}


3、观察者模式

3.1、定义

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

3.2、背景

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

3.3、要点

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

3.4、没使用设计模式实现

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


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

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

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

class WeatherData {
};

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

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

3.5、使用设计模式实现

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

#include 

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

class DisplayA : public IDisplay {
public:
    virtual void Show(float temperature);
private:
    void jianyi();
};

class DisplayB : public IDisplay{
public:
    virtual void Show(float temperature);
};

class DisplayC : public IDisplay{
public:
    virtual void Show(float temperature);
};

class WeatherData {
};

class DataCenter {
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 = new DataCenter;
    IDisplay *da = new DisplayA();
    IDisplay *db = new DisplayB();
    IDisplay *dc = new DisplayC();
    center->Attach(da);
    center->Attach(db);
    center->Attach(dc);


    
    center->Notify();
    
    //-----
    center->Detach(db);
    center->Notify();
    return 0;
}

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++  游戏开发  脚本语言
class Promotion {
    VacationEnum vac;
public:
    double CalcPromotion(){
        if (vac == VAC_Spring {
            // 春节
        }
        else if (vac == VAC_QiXi) {
            // 七夕
        }
        else if (vac == VAC_Wuyi) {
            // 五一
        }
		else if (vac == VAC_GuoQing) {
			// 国庆
		}
        else if (vac == VAC_ShengDan) {

        }
     }
    
};

4.5、使用设计模式实现

class Context {

};

class ProStategy {
public:
    virtual double CalcPro(const Context &ctx) = 0;
    virtual ~ProStategy(); 
};
// cpp
class VAC_Spring : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi1  : public VAC_QiXi {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

class VAC_Shengdan : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

class Promotion {
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 = new VAC_QiXi1();
    Promotion *p = new Promotion(s);
    p->CalcPromotion(ctx);
    return 0;
}

未完!!!

你可能感兴趣的:(Linux,系统编程,c++,设计模式,学习)