博客园  :: 首页  :: 新随笔  :: 管理

1.2.1 创建型设计模式

Posted on 2022-10-21 00:54  wsg_blog  阅读(29)  评论(0编辑  收藏  举报

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)的指针指向即可