协议解析必用的责任链模式

书籍

《设计模式 - 可复⽤⾯向对象软件的基础》
《重构与模式》

设计模式

设计模式是指在软件开发中,经过验证的,⽤于解决在特定环境下,重复出现的,特定问题的解决⽅案;

内存模型:

扩展:c语⾔当中的多态
        redis
        nginx

模式设计原则:

依赖倒置原则
⾼层模块不应该依赖低层模块,⼆者都应该依赖 抽象
抽象不应该依赖具体实现,具体实现应该依赖于抽象;

⾃动驾驶系统公司是⾼层,汽⻋⽣产⼚商为低层,它们不应该互相依赖,⼀⽅变动另⼀⽅也会
跟着变动;⽽应该 抽象 ⼀个⾃动驾驶⾏业标准,⾼层和低层都依赖它;这样以来就解耦了两⽅
的变动;⾃动驾驶系统、汽⻋⽣产⼚商都是具体实现,它们应该都依赖⾃动驾驶⾏业标准(抽
象);
开放封闭原则
⼀个类应该对扩展开放,对修改关闭;
⾯向接⼝编程
不将变量类型声明为某个特定的具体类,⽽是声明为某个接⼝。 客户程序⽆需获知对象的具体类型,只需要知道对象所具有的接⼝。
减少系统中各部分的依赖关系,从⽽实现 ⾼内聚、松耦合 的类型设计⽅案。
封装变化点
将稳定点和变化点分离,扩展修改变化点; 让稳定点与变化点的实现层次分离
单⼀职责原则
⼀个类应该仅有⼀个引起它变化的原因;
⾥⽒替换原则
⼦类型必须能够替换掉它的⽗类型;主要出现在⼦类覆盖⽗类实现,原来使⽤⽗类型的程序可
能出现错误;覆盖了⽗类⽅法却没实现⽗类⽅法的 职责
接⼝隔离原则
不应该强迫客户依赖于他们不⽤的⽅法;
⼀般⽤于处理⼀个类拥有⽐较多的接⼝,⽽这些接⼝涉及到很多职责;
对象组合优于类继承
继承 耦合度 ⾼, 组合 耦合度低;

什么情况下使⽤设计模式?

系统的关键依赖点;
能明确找到变化点;
能明确找到复⽤⽅向;
对需求变化⽅向熟悉;
如何找到设计模式?
从重构中获得;
重构
静态转变为动态;
早绑定转变为晚绑定;
继承转变为组合;
编译时依赖转变为运⾏时依赖;
紧耦合转变为松耦合;
为什么要学习设计模式?
从已有的且证明有效的设计模式中获取灵感,少⾛弯路;
通⽤语⾔,知道在已有的设计模式扩展代码;
体会模式设计,设计⾃⼰的⾏之有效的设计模式;
学习设计模式的步骤
深刻体会上⾯的原则;
理解设计模式,能 知道设计模式的变化点和稳定点
能在已使⽤的设计模式中,知道如何写扩展;
能在复杂需求中,抽象出已有设计模式; 能在重构中,开发⾃⼰的设计模式;
能在重构中,开发⾃⼰的设计模式;

模板⽅法

定义
定义⼀个操作中的算法的⻣架 ,⽽将⼀些步骤延迟到⼦类中。 Template Method 使得⼦类可以不
改变⼀个算法的结构即可重定义该算法的某些特定步骤。 —— 《 设计模式》 GoF
背景
某个品牌动物园,有⼀套固定的表演流程,但是其中有若⼲个表演⼦流程受欢迎程度⽐较低,希望
将这⼏个表演流程创新,以尝试迭代更新表演流程;
代码
#include <iostream>
using namespace std;

class ZooShow {
public:
    // 固定流程封装到这里
    void Show() {
        Show0();
        Show1();
        Show2();
        Show3();
    }
protected:
    // 子流程 使用protected保护起来 不被客户调用 但允许子类扩展
    virtual void Show0(){
        cout << "show0" << endl;
    }
    virtual void Show2(){
        cout << "show2" << endl;
    }
    virtual void Show1() {

    }
    virtual void Show3() {

    }
};
class ZooShowEx : public ZooShow {
protected:
    virtual void Show1(){
        cout << "show1" << endl;
    }
    virtual void Show3(){
        cout << "show3" << endl;
    }
    virtual void Show4() {
        //
    }
};

class ZooShowEx1 : public ZooShow {
protected:
    virtual void Show0(){
        cout << "show1" << endl;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};

class ZooShowEx2 : public ZooShow {
protected:
    virtual void Show1(){
        cout << "show1" << endl;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};
/*
依赖倒置原则
单一职责原则
接口隔离原则

反向控制:应用程序 框架 应用程序(变化的)应该依赖框架(稳定的),应该是框架去调应用程序,而不是应用程序去调框架
*/
int main () {
    ZooShow *zs = new ZooShowEx;
    ZooShow *zs1 = new ZooShowEx1;
    ZooShow *zs2 = new ZooShowEx2;
    zs->Show();
    return 0;
}

要点
⾮常常⽤的设计模式,⼦类可以复写⽗类的⼦流程,使⽗类的⼤流程更丰富;
反向控制流程的典型应⽤;
⽗类 protected 保护⼦类需要复写的⼦流程;这样⼦类的⼦流程只能⽗类来调⽤;
充分体现了依赖倒置原则;
本质
通过固定算法⻣架来约束⼦类的⾏为;
结构图

观察者模式

定义
定义对象间的⼀种⼀对多(变化)的依赖关系,以便当⼀个对象 (Subject) 的状态发⽣改变时,所有
依赖于它的对象都得到通知并⾃动更新。 —— 《 设计模式》 GoF
背景
⽓象站发布⽓象资料给数据中⼼,数据中⼼经过处理,将⽓象信息更新到两个不同的显示终端( A
B );
代码
#include <vector>

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

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

class DisplayB : 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();
    center->Attach(da);
    center->Attach(db);
    center->Notify();
    
    //-----
    center->Detach(db);
    center->Notify();
    return 0;
}

要点
观察者模式使得我们可以独⽴地改变⽬标与观察者,从⽽使⼆者之间的关系松耦合;
观察者⾃⼰决定是否订阅通知,⽬标对象并不关注谁订阅了;
观察者不要依赖通知顺序,⽬标对象也不知道通知顺序;
常使⽤在基于事件的 ui 框架中,也是 MVC 的组成部分;
常使⽤在分布式系统中, actor 框架中;
本质
触发联动;
结构图

策略模式

定义
定义⼀系列算法,把它们⼀个个封装起来,并且使它们可互相替换。该模式使得算法可独⽴于使⽤
它的客户程序⽽变化。 —— 《设计模式》 GoF
背景
某商场节假⽇有固定促销活动,为了加⼤促销⼒度,现提升国庆节促销活动规格;
代码
要点
策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法
之间进⾏切换;
策略模式消除了条件判断语句;就是在解耦合;
充分体现了开闭原则;单⼀职责;
本质
分离算法,选择实现;
结构图

责任链模式

定义
使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间的耦合关系。将这些对象连成
⼀条链,并沿着这条链传递请求,直到有⼀个对象处理它为⽌。 —— 《设计模式》 GoF
背景
请假流程, 1 天内需要主程序批准, 3 天内需要项⽬经理批准, 3 天以上需要⽼板批准;
代码
class Context {
public:
    std::string name;
    int day;
};


class IHandler {
public:
    virtual ~IHandler() {}
    void SetNextHandler(IHandler *next) {
        next = next;
    }
    bool Handle(ctx) {
        if (CanHandle(ctx)) {
            return HandleRequest();
        } else if (GetNextHandler()) {
            return GetNextHandler()->HandleRequest(ctx);
        } else {
            // err
        }
    }
protected:
    virtual bool HandleRequest(const Context &ctx) = 0;
    virtual bool CanHandle(const Context &ctx) =0;
    IHandler * GetNextHandler() {
        return next;
    }
private:
    IHandler *next;
};

class HandleByMainProgram : public IHandler {
protected:
    virtual bool HandleRequest(const Context &ctx){
        //
    }
    virtual bool CanHandle() {
        //
    }
};

class HandleByProjMgr : public IHandler {
protected:
    virtual bool HandleRequest(const Context &ctx){
        //
    }
    virtual bool CanHandle() {
        //
    }
};
class HandleByBoss : public IHandler {
public:
    virtual bool HandleRequest(const Context &ctx){
        //
    }
protected:
    virtual bool CanHandle() {
        //
    }
};

int main () {
    IHandler * h1 = new MainProgram();
    IHandler * h2 = new HandleByProjMgr();
    IHandler * h3 = new HandleByBoss();
    h1->SetNextHandler(h2);

    Context ctx;
    h1->handle(ctx);
    return 0;
}

nginx 阶段处理
// 严格意义说是功能链
// ngx_http_init_phase_handlers 初始化责任链 cmcf->phase_engine.handlers
// ngx_http_core_run_phases 调⽤责任链
要点
解耦请求⽅和处理⽅,请求⽅不知道请求是如何被处理,处理⽅的组成是由相互独⽴的⼦处理
构成,⼦处理流程通过链表的⽅式连接,⼦处理请求可以按任意顺序组合;
责任链请求强调请求最终由⼀个⼦处理流程处理;通过了各个⼦处理条件判断;
责任链扩展就是功能链,功能链强调的是,⼀个请求依次经由功能链中的⼦处理流程处理;
充分体现了单⼀职责原则;将职责以及职责顺序运⾏进⾏抽象,那么职责变化可以任意扩展,
同时职责顺序也可以任意扩展;
本质
分离职责,动态组合;
结构图

装饰器模式

定义
动态地给⼀个对象增加⼀些额外的职责。就增加功能⽽⾔,装饰器模式⽐⽣成⼦类更为灵活。 ——
《设计模式》 GoF
背景
普通员⼯有销售奖⾦,累计奖⾦,部⻔经理除此之外还有团队奖⾦;后⾯可能会添加环⽐增⻓奖
⾦,同时可能针对不同的职位产⽣不同的奖⾦组合;

代码
// 普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖金,同时可能产生不同的奖金组合;
// 销售奖金 = 当月销售额 * 4%
// 累计奖金 = 总的回款额 * 0.2%
// 部门奖金 = 团队销售额 * 1%
// 环比奖金 = (当月销售额-上月销售额) * 1%
// 销售后面的参数可能会调整
class Context {
public:
    bool isMgr;
    // User user;
    // double groupsale;
};

// 试着从职责出发,将职责抽象出来
class CalcBonus {    
public:
    CalcBonus(CalcBonus * c = nullptr) {}
    virtual double Calc(Context &ctx) {
        return 0.0; // 基本工资
    }
    virtual ~CalcBonus() {}

protected:
    CalcBonus* cc;
};

class CalcMonthBonus : public CalcBonus {
public:
    CalcMonthBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double mbonus /*= 计算流程忽略*/; 
        return mbonus + cc->Calc(ctx);
    }
};

class CalcSumBonus : public CalcBonus {
public:
    CalcSumBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double sbonus /*= 计算流程忽略*/; 
        return sbonus + cc->Calc(ctx);
    }
};

class CalcGroupBonus : public CalcBonus {
public:
    CalcGroupBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};

class CalcCycleBonus : public CalcBonus {
public:
    CalcGroupBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};

int main() {
    // 1. 普通员工
    Context ctx1;
    CalcBonus *base = new CalcBonus();
    CalcBonus *cb1 = new CalcMonthBonus(base);
    CalcBonus *cb2 = new CalcSumBonus(cb1);
    cb2->Calc(ctx1);
    // 2. 部门经理
    Context ctx2;
    CalcBonus *cb3 = new CalcGroupBonus(cb2);
    cb3->Calc(ctx2);
}

要点
通过采⽤组合⽽⾮继承的⼿法, 装饰器模式实现了在运⾏时动态扩展对象功能的能⼒,⽽且
可以根据需要扩展多个功能。 避免了使⽤继承带来的 灵活性差 多⼦类衍⽣问题 。不是解决“ 多⼦类衍⽣的多继承 问题,⽽是解决 ⽗类在多个⽅向上的扩展功能 问题;装饰器模式把⼀系列复杂的功能分散到每个装饰器当中,⼀般⼀个装饰器只实现⼀个功能,实现复⽤装饰器的功能;
本质
动态组合
结构图

单例模式

定义
保证⼀个类仅有⼀个实例,并提供⼀个该实例的全局访问点。 —— 《设计模式》 GoF
代码
版本 1
  线程不安全,且内存泄漏
// 内存栈区
// 内存堆区
// 常数区
// 静态区 系统释放
// ⼆进制代码区
class Singleton{
public:
    static Singleton* GetInstance(){
        if(_instance == nullptr){
            _instance = new Singleton();
        }
        return _instance;
    }
private:
    Singleton(){} // 构造
    Singleton(const Singleton& that){} // 拷贝构造
    Singleton& operator=(const Singleton& that){} // 拷贝赋值
    static Singleton* _instance;
};
Singleton* Singleton::_instance == nullptr;// 静态成员需要初始化

版本2

class Singleton {
public:
 static Singleton * GetInstance() {
     if (_instance == nullptr) {
         _instance = new Singleton();
         atexit(Destructor);
     }
     return _instance;
 }
     ~Singleton() {}

 /*   class GC{
        ~GC(){
            delete _instance;
        }
      } */
private:
 static void Destructor() {
     if (nullptr != _instance) {
         delete _instance;
         _instance = nullptr;
     }
 }
 Singleton();//构造
 Singleton(const Singleton &cpy); //拷⻉构造
 Singleton& operator=(const Singleton&) {}
 static Singleton * _instance; 
 /* static GC gc; */
}
 Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
 /* Singleton::GC gc; */
// 还可以使⽤ 内部类,智能指针来解决; 此时还有线程安全问题

版本3

#include <mutex>
class Singleton { // 懒汉模式 lazy load
public:
     static Singleton * GetInstance() {
     //std::lock_guard<std::mutex> lock(_mutex); // 3.1 切换线程   锁的粒度大
     if (_instance == nullptr) {
             std::lock_guard<std::mutex> lock(_mutex); // 3.2  
             if (_instance == nullptr) {
                 /*pthread_once_t once_control = PTHREAD_ONCE_INIT;
                 pthread_once(once_control , init);*/
                 _instance = new Singleton();  // --->   1分配内存,2调用构造函数,3赋值
                 atexit(Destructor);           // ---> 多线程环境下 cpu会进行重排
             }                                 // --->  可能调用顺序是132
     }                                         // 晚到来的线程拿到_instance不等于null
     return _instance;                         // 直接返回,此时构造函数还没执行完
 }
private:
 static void init(void){
    _instance = new Singleton();
 }
 static void Destructor() {
     if (nullptr != _instance) {
         delete _instance;
         _instance = nullptr;
     }
 }
 Singleton(){} //构造
 Singleton(const Singleton &cpy){} //拷⻉构造
 Singleton& operator=(const Singleton&) {}
 static Singleton * _instance;
 static std::mutex _mutex; }
 Singleton* Singleton::_instance = nullptr;//静态成员需要初始化
 std::mutex Singleton::_mutex; //互斥锁初始化

版本4

#include <atomic>           //懒汉式
#include <mutex>
class Singleton{
public:
    static Singleton* GetInstance(){
        Singleton* tmp = _instance.load(std::memory_order_relaxed);//把_instance取出
        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 = new Singleton;
                std::atomic_thread_fence(std::memory_order_release);//释放内存屏障
                _instance.store(tmp , std::memory_order_relaxed);//把tmp存入_instance
                atexit(Destructor);
            }
        }
        return tmp;
    }

private:
    static void Destructor(){
        Singleton* tmp = _instance.load(std::memory_order_relaxed);
        if(nullptr != tmp){
            delete tmp;
        }
    }
    Singleton(){}
    Singleton(const Singleton& that){}
    Singleton& operator=(const Singleton& that){}
    static std::atomic<Singleton*> _instance;
    static std::mutex _mutex;
};
std::atomic<Singleton*> Singleton::_instance;
std::mutex Singleton::_mutex;

版本5

// c++11 magic static 特性:如果当静态变量在初始化的时候,并发同时进⼊声明语句,并发
线程将会阻塞等待初始化结束。
class Singleton
{
public:
 ~Singleton(){}
 static Singleton& GetInstance() {
 static Singleton instance;
 return instance;
 } 
private:              //构造函数私有,无法继承,子类无法实例化父类
 Singleton(){}       
 Singleton(const Singleton&) {}
 Singleton& operator=(const Singleton&) {}
};
// 继承 Singleton
// g++ Singleton.cpp -o singleton -std=c++11
/*该版本具备 版本5 所有优点:
1. 利⽤静态局部变量特性,延迟加载;
2. 利⽤静态局部变量特性,系统⾃动回收内存,⾃动调⽤析构函数;
3. 静态局部变量初始化时,没有 new 操作带来的cpu指令reorder操作;
4. c++11 静态局部变量初始化时,具备线程安全;
*/

版本6

template<typename T>
class Singleton {
public:
 static T& GetInstance() {
 static T instance; // 这⾥要初始化DesignPattern,需要调⽤
DesignPattern 构造函数,同时会调⽤⽗类的构造函数。
 return instance;
 }
protected:
 virtual ~Singleton() {}
 Singleton() {} // protected修饰构造函数,才能让别⼈继承
 Singleton(const Singleton&) {}
 Singleton& operator =(const Singleton&) {}
};
class DesignPattern : public Singleton<DesignPattern> {
 friend class Singleton<DesignPattern>; // friend 能让 Singleton<T> 访
问到 DesignPattern构造函数
private:
 DesignPattern(){}
 DesignPattern(const DesignPattern&) {}
 DesignPattern& operator=(const DesignPattern&) {}
}
要点
结构图

策略模式

定义
定义⼀系列算法,把它们⼀个个封装起来,并且使它们可互相替换。该模式使得算法可独⽴于使⽤
它的客户程序⽽变化。 —— 《设计模式》 GoF
背景
某商场节假⽇有固定促销活动,为了加⼤促销⼒度,现提升国庆节促销活动规格;
代码
要点
策略模式提供了⼀系列可重⽤的算法,从⽽可以使得类型在运⾏时⽅便地根据需要在各个算法
之间进⾏切换;
策略模式消除了条件判断语句;就是在解耦合;
充分体现了开闭原则;单⼀职责;
本质
分离算法,选择实现;
结构图

责任链模式

定义
使多个对象都有机会处理请求,从⽽避免请求的发送者和接收者之间的耦合关系。将这些对象连成
⼀条链,并沿着这条链传递请求,直到有⼀个对象处理它为⽌。 —— 《设计模式》 GoF
背景
请假流程, 1 天内需要主程序批准, 3 天内需要项⽬经理批准, 3 天以上需要⽼板批准;
代码
nginx 阶段处理
// 严格意义说是功能链
// ngx_http_init_phase_handlers 初始化责任链 cmcf->phase_engine.handlers
// ngx_http_core_run_phases 调⽤责任链
要点
解耦请求⽅和处理⽅,请求⽅不知道请求是如何被处理,处理⽅的组成是由相互独⽴的⼦处理
构成,⼦处理流程通过链表的⽅式连接,⼦处理请求可以按任意顺序组合;
责任链请求强调请求最终由⼀个⼦处理流程处理;通过了各个⼦处理条件判断;
责任链扩展就是功能链,功能链强调的是,⼀个请求依次经由功能链中的⼦处理流程处理;
充分体现了单⼀职责原则;将职责以及职责顺序运⾏进⾏抽象,那么职责变化可以任意扩展,
同时职责顺序也可以任意扩展;
本质
分离职责,动态组合;
结构图

⼯⼚⽅法模式

定义
定义⼀个⽤于创建对象的接⼝,让⼦类决定实例化哪⼀个类。 Factory Method 使得⼀个类的实例化
延迟到⼦类。 —— 《设计模式》 GoF
背景
实现⼀个导出数据的接⼝,让客户选择数据的导出⽅式;
代码
要点
解决 创建过程⽐较复杂 ,希望对外隐藏这些细节;
⽐如连接池,线程池;
隐藏对象真实类型;
对象创建会有很多参数来决定如何创建;
创建对象有复杂的依赖关系;
本质
延迟到⼦类来选择实现;
结构图

抽象⼯⼚模式

定义
提供⼀个接⼝,让该接⼝负责创建⼀系列 相关或者相互依赖的对象 ,⽆需指定它们具体的类。
—— 《设计模式》 GoF
背景
实现⼀个拥有导出导⼊数据的接⼝,让客户选择数据的导出导⼊⽅式;
代码
要点
本质
结构图

适配器模式

定义
将⼀个类的接⼝转换成客户希望的另⼀个接⼝。 Adapter 模式使得原本由于接⼝不兼容⽽不能⼀起
⼯作的那些类可以⼀起⼯作。 —— 《设计模式》 GoF
背景
⽇志系统,原来是通过写磁盘的⽅式进⾏存储,后来因为查询不便,需要额外添加往数据库写⽇志
的功能(写⽂件和数据库并存);
代码
要点
原来的接⼝是稳定的,新的外来的需求是变化的,那么可以通过继承原来的接⼝,让原来的接
⼝继续保持稳定,在⼦类通过组合的⽅式来扩展功能;
本质
转换匹配,复⽤功能;

结构图

代理模式

定义
为其他对象提供⼀种代理以控制对这对象的访问。 —— 《设计模式》 GoF
背景
在有些系统中,为了某些对象的纯粹性,只进⾏了功能相关封装(稳定点),后期添加了其他功能
需要对该对象进⾏额外操作(变化点),为了隔离变化点(也就是不直接在稳定点进⾏修改,这样
会让稳定点也变得不稳定),可以抽象⼀层代理层;
代码
要点
远程代理(隐藏⼀个对象存在不同的地址空间的事实),虚代理(延迟加载 lazyload ),保护
代理(在代理前后做额外操作,权限管理,引⽤计数等);
在分布式系统中, actor 模型( skynet )等常⽤的设计模式;
本质
控制对象访问;
结构图

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值