设计模式总结上篇

概述

设计模式是什么?

  1. 设计模式是在软件开发中,经过验证的,用于解决在特定环境下,重复出现的,特定问题的解决方案。
  2. 是解决问题的一些固定套路
  3. 慎用设计模式(精通设计模式要有一定的工程代码量)

设计模式怎么来的?

满足设计原则后,进而慢慢迭代出来的

解决了什么问题?

前提:具体的需求既有稳定点,又有变化点。

以下两种不需要使用设计模式:

  1. 全是稳定点(需求稳定)
  2. 全是变化点(例如:游戏开发)

设计模式期望来修改少量的代码,就可以适应需求的变化

一个比喻:
需求:整洁的房间,一只好动的毛,怎么保证环境的整洁?
方案:把猫关进笼子里

使用设计模式,让变化点在有限范围内变化。

设计模式基础

  1. 面向对象的思想
    封装:隐藏实现细节,实现模块化
    继承:无需修改原有类,通过继承实现对功能的扩展
    多态:静态多态(函数重载)
    动态多态(虚函数)
  2. 设计原则
    依赖倒置
    开闭 对扩展开放,对修改关闭 封装,多态
    面向接口 封装
    封装变化点
    单一职责 封装
    里氏替换 多态
    接口隔离
    组合优于继承
    最小知道原则 封装

如何学习设计模式?

明确目的

  1. 要懂得在现有基础上,扩展代码(公司已经有了)
  2. 做功能抽象时,如何选择设计模式

学习的步骤

  1. 设计模式解决了什么问题?(稳定/变化点)
  2. 该设计模式的代码结构是什么?
  3. 符合哪些设计原则 如何扩展代码?(针对变化点)
  4. 知道该设计模式的典型应用场景?(工作场景中/开源框架中)

设计模式

1. 模板方法

  1. 定义
    定义一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。
    Template Method使得子类可以不改变一个算法的结构即可重
    定义该算法的某些特定步骤。

  2. 解决的问题
    稳定点:算法骨架
    变化点:子流程需要变化

  3. 代码结构
    基类中有骨架流程接口
    所有子流程对子类开放并且是虚函数
    多态的使用方式(基类指针指向子类的对象)

  4. 符合的设计原则
    单一职责

开闭

依赖倒置:
子类扩展时,需要依赖积累的虚函数
使用者只依赖接口

封装变化点:protected

  1. 示例代码
#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;
}


  1. 如何扩展
    实现子类继承基类,复写子流程
    通过多态调用方式使用

2.观察者模式

  1. 定义
    定义对象间的一种一对多(变化)的依赖关系,以便当一个对
    象(Subject)的状态发生改变时,所有依赖于它的对象都得到通
    知并自动更新。

  2. 解决的问题
    稳定点:一对多的依赖关系(依赖关系是稳定的),一变化则多跟着变化
    变化点: 多增加/多减少

  3. 代码结构

  4. 符合的设计原则
    面向接口编程
    接口隔离:类和类依赖于一个接口上
    封装变化点:

  5. 代码示例

// 背景:气象站发布气象资料给数据中心,数据中心经过处理,将气象
// 信息更新到两个不同的显示终端(A 和B);
#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 DisplayC : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC Show" << endl;
    }
};

class DisplayD : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC 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);
    
    IDisplay *dc = new DisplayC();
    center->Attach(dc);

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


    //....
    center->Attach(dd);

    center->Notify();
    return 0;
}
  1. 如何扩展
    增加一个类,继承

3. 策略模式

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

  2. 解决了什么问题
    稳定点:客户程序与算法的调用关系
    变化点:新加算法/算法内容改变

3.代码结构

4.设计原则
接口隔离:依赖注入,一个接口解决两个类的依赖

  1. 示例代码
// 某商场节假日有固定促销活动,为了加大促销力度,现提升国
// 庆节促销活动规格;
// 
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值