• 结构型设计模式学习笔记


    单例模式

    定义

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

    版本一

    可以发现C++中 ostream就有点类似这个样子,禁止了拷贝和构造函数

    class Singleton{
    public:
        static Singleton * GetInstance(){
    		if(_instance == nullptr){
                //线程不安全,Singleton对象可能被重复创建
    			_instance = new Singleton(); //在堆区开辟空间
            }
            return _instance;
        }
    private:
        Singletion(){} //构造,禁止用户自己调用
        ~Singleton(){}
        Singleton(const Singleton &clone){} //copy constructor
        Singleton& operator=(const Singleton&) {}
        static Singleton * _instance; //静态成员存放在全局区(global variables也是)
    };
    Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    缺点
    • 线程不安全,Singleton对象可能被重复创建
    • new出的实例在进程退出时不会调用析构函数**(不理解?)**
    版本二

    解决了没有析构对象的问题

    class Singleton{
    public:
        static Singleton * GetInstance(){
    		if(_instance == nullptr){
    			_instance = new Singleton(); //在堆区开辟空间
                atexit(Destructor); //进程终止时调用Destructor函数
            }
            return _instance;
        }
    private:
        //静态成员是归属于整个类的,所以在进程退出时可以被调用
        static void Destructor(){
    		if(nullptr != _instance)
            {
    			delete _instance;
                _instance = nullptr;
            }
        }
        Singletion(){} //构造,禁止用户自己调用
        ~Singleton(){}
        Singleton(const Singleton &clone){} //copy constructor
        Singleton& operator=(const Singleton&) {}
        static Singleton * _instance; //静态成员存放在全局区(global variables也是)
    };
    Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
    //还可以使用内部类 或者智能指针来解决,此时还有线程安全问题
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    版本三

    该版本称为懒汉模式 lazy load,解决了多线程环境下可能多次new Singleton对象

    class Singleton{
    public:
        static Singleton * GetInstance(){
    		//std::lock_guard lock(_mutex); 3.1切换线程
            if(_instance == nullptr){
                std::lock_guard<std::mutex> lock(_mutex); //3.2
    			if(_instance == nullptr){ //if判断防止多线程时重复new 对象
                   _instance = new Singleton(); //在堆区开辟空间
                    // new有三步操作:
                    //1. 分配内存
                    //2. 调用构造函数
                    //3. 返回指针
                    //但是在多线程环境下 有cpu reorder操作
                    //导致顺序为1 3 2,从而没调用构造函数,导致_instance为野指针了。
                    atexit(Destructor); 
                }
                 
            }
            return _instance;
        }
    private:
        static void Destructor(){
    		if(nullptr != _instance)
            {
    			delete _instance;
                _instance = nullptr;
            }
        }
        Singletion(){} //构造,禁止用户自己调用
        ~Singleton(){}
        Singleton(const Singleton &clone){} //copy constructor
        Singleton& operator=(const Singleton&) {}
        static Singleton * _instance; //静态成员存放在全局区(global variables也是)
        static std::mutex _mutex; //!!!
    };
    Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
    std::mutex Singleton::_mutex;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    如果采用3.1处加锁而注释 3.2 ,则锁“太重”,因为创建对象只有一次,而如果加在 3.1 处,则后来获取指针来读对象时也需要加锁开销太大。

    版本四

    该版本使用内存屏障解决CPU reorder问题

    class Singleton{
    public:
        static Singleton * GetInstance(){
            Singleton *tmp = _instance.load(std::memory_order_relaxed);//4.2 
            std::atomic_thread_fence(std::memory_order_acquire);//4.1 获取内存屏障
            if(_instance == nullptr){
                std::lock_guard<std::mutex> lock(_mutex); //
    			if(_instance == nullptr){ //if判断防止多线程时重复new 对象
                   _instance = new Singleton(); //此时new三步骤按顺序进行
                   std::atomic_thread_fence(std::memory_order_release);//释放内存屏障 ,与4.1对应
                   _instance.store(tmp, std::memory_order_relaxed);// 与4.2对应,可理解为保持原子性
                   atexit(Destructor); 
                }
                 
            }
            return _instance;
        }
    private:
        static void Destructor(){
    		if(nullptr != _instance)
            {
    			delete _instance;
                _instance = nullptr;
            }
        }
        Singletion(){} //构造,禁止用户自己调用
        ~Singleton(){}
        Singleton(const Singleton &clone){} //copy constructor
        Singleton& operator=(const Singleton&) {}
        static Singleton * _instance; //静态成员存放在全局区(global variables也是)
        static std::mutex _mutex; //!!!
    };
    Singleton* Singleton::_instance = nullptr; // 静态成员,类内声明类外初始化
    std::mutex Singleton::_mutex;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    这里内存屏障相关知识点可自行搜索学习,这里只给出解决方案。

    版本五(推荐该版本进行默写)

    使用c++11 magic static特性,如果当变量在初始化时,并发线程同时进入声明语句,则会阻塞等待直到初始化结束

    该方法在effective C++ 中有提及

    class Singleton
    {
    public:
        static Singleton& GetInstance(){
            
            static Singleton instance;//存储在静态全局区
            return instance;
        }
    
    private:
        Singleton(){}
        ~Singleton(){}
        Singleton(const Singleton&){}
        Singleton& operator=(const Singleton&){}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    优点
    • 静态局部变量特性:延迟加载
    • C++11静态局部变量初始化时,具备线程安全
    • 静态局部变量特性:系统**自动回收内存,**自动调用析构函数
    • 静态局部变量初始化时,没有new操作带来的cpu指令reorder操作
    版本六

    该版本利用模板提高了复用性,使得其他类通过单例基类来实现单例模式。

    template<typename T>
    class Singleton
    {
    public:
        static T& GetInstance(){
            static T instance; // 这里会调用T类型(子)构造函数,和父类的构造函数
            return instance;
        }
    
    private:
        Singleton(){}
        virtual ~Singleton(){}
        Singleton(const Singleton&){}
        Singleton& operator=(const Singleton&){}
    };
    
    class DesignPattern : public Singleton<DesignPattern>{
        friend class Singleton<DesignPattern>; //使得父类可以调用本类的构造函数
    public:
        ~DesignPattern(){}
    private:
        DesingPattern(){}
        DesignPattern(const DesignPattern&){}
        DesginPattern& operator=(const DesignPattern&){}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    结构图

    在这里插入图片描述

    工厂方法

    定义

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

    例子

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

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

    延迟到子类来选择实现

    结构图

    在这里插入图片描述

    示例代码一
    // 实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv
    class IExport {
    public:
        virtual bool Export(const std::string &data) = 0;
        virtual ~IExport(){}
    };
    
    class ExportXml : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportJson : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    // csv
    class ExportTxt : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    int main() {
        std::string choose/* = */;
        if (choose == "txt") {
            /***/
            IExport *e = new ExportTxt();
            /***/
            e->Export("hello world");
        } else if (choose == "json") {
            /***/
            IExport *e = new ExportJson();
            /***/
            e->Export("hello world");
        } else if (choose == "xml") {
            IExport *e = new ExportXml();
            e->Export("hello world");
        } else if (choose == "csv") {
            IExport *e = new ExportXml();
            e->Export("hello world");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    示例代码二
    class IExport {
    public:
        virtual bool Export(const std::string &data) = 0;
        virtual ~IExport(){}
    };
    
    class ExportXml : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportJson : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportTxt : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class IExportFactory {
    public:
        virtual IExport * NewExport(/* ... */) = 0;
    };
    
    class ExportXmlFactory : public IExportFactory {
    public:
        //将对象创建过程也封装起来
        IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportXml;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class ExportJsonFactory : public IExportFactory {
    public:
        IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportJson;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class ExportTxtFactory : public IExportFactory {
    public:
        IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportTxt;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class ExportData {
    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");
        return 0;
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    示例代码三
    class IExport {
    public:
        virtual bool Export(const std::string &data) = 0;
        virtual ~IExport(){}
    };
    
    class ExportXml : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportJson : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportTxt : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportCSV : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    //工厂基类
    class IExportFactory {
    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;
    };
    
    class ExportXmlFactory : public IExportFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportXml();
            // 可能之后有什么操作
            return temp;
        }
    };
    class ExportJsonFactory : public IExportFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportJson;
            // 可能之后有什么操作
            return temp;
        }
    };
    class ExportTxtFactory : public IExportFactory {
    protected:
        IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportTxt;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class ExportCSVFactory : public IExportFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportCSV;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    int main () {
        IExportFactory *factory = new ExportTxtFactory();
        factory->Export("hello world");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    注解
    • 工厂模式通常会结合模板模式 和 单例模式使用

    • 工厂模式一般用于封装某些对用户无需可见的操作(如new)

    抽象工厂

    定义

    提供一个接口,让该接口负责创建一系列 相关或者相互依赖的对象,无需指定它们具体的类

    例子

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

    结构图

    在这里插入图片描述

    示例代码

    下面代码主要是封装相关性,而实际工作中是封装依赖性为多。

    class IExport {
    public:
        virtual bool Export(const std::string &data) = 0;
        virtual ~IExport(){}
    };
    
    class ExportXml : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportJson : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportTxt : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class ExportCSV : public IExport {
    public:
        virtual bool Export(const std::string &data) {
            return true;
        }
    };
    
    class IImport {
    public:
        virtual bool Import(const std::string &data) = 0;
        virtual ~IImport(){}
    };
    
    class ImportXml : public IImport {
    public:
        virtual bool Import(const std::string &data) {
            return true;
        }
    };
    
    class ImportJson : public IImport {
    public:
        virtual bool Import(const std::string &data) {
            return true;
        }
    };
    
    class ImportTxt : public IImport {
    public:
        virtual bool Import(const std::string &data) {
            return true;
        }
    };
    
    // 对于初学者: 知道扩展代码
    // 5年
    class ImportCSV : public IImport {
    public:
        virtual bool Import(const std::string &data) {
            // ....
            return true;
        }
    };
    
    //!!!关键接口类
    class IDataApiFactory {
    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;
    };
    
    class XmlApiFactory : public IDataApiFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportXml;
            // 可能之后有什么操作
            return temp;
        }
        virtual IImport * NewImport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IImport * temp = new ImportXml;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class JsonApiFactory : public IDataApiFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportJson;
            // 可能之后有什么操作
            return temp;
        }
        virtual IImport * NewImport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IImport * temp = new ImportJson;
            // 可能之后有什么操作
            return temp;
        }
    };
    class TxtApiFactory : public IDataApiFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportTxt;
            // 可能之后有什么操作
            return temp;
        }
        virtual IImport * NewImport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IImport * temp = new ImportTxt;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    class CSVApiFactory : public IDataApiFactory {
    protected:
        virtual IExport * NewExport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IExport * temp = new ExportCSV;
            // 可能之后有什么操作
            return temp;
        }
        virtual IImport * NewImport(/* ... */) {
            // 可能有其它操作,或者许多参数
            IImport * temp = new ImportCSV;
            // 可能之后有什么操作
            return temp;
        }
    };
    
    // 相关性  依赖性    工作当中
    int main () {
        IDataApiFactory *factory = new CSVApiFactory();
        factory->Import("hello world");
        factory->Export("hello world");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178

    责任链

    定义

    使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

    Nginx代码就是利用了责任链,它将http请求分为了11个阶段,如accept、header处理(token登录验证)、body处理.

    例子

    请求流程:1天内需要主程序员批准,3天内需要项目经理批准,3天以上需要老板批准

    稳定点:处理流程

    变化点:请假天数,处理链条长度,谁来处理

    对稳定点进行抽象,对变化点进行扩展

    要点
    • 解耦请求方和处理方,请求方不知道请求如何被处理,处理方的组成是由相互独立的子处理构成,子处理流程通过链表方式连接,子处理请求可以按任意顺序组合
    • 责任链请求强调请求最终由一个子处理流程处理;通过各个子处理条件判断
    • 责任链扩展就是功能链,功能链强调的是,一个请求依次经由功能链中的子处理流程处理
    • 将职责链以及职责顺序运行进行抽象,那么职责变化可以任意扩展,同时职责顺序也可以任意扩展。
    本质

    分离职责,动态组合

    结构图

    在这里插入图片描述

    示例代码
    class Context {
    public:
        std::string name;
        int day;
    };
    
    // !!!稳定点 抽象  变化点 扩展
    class IHandler {
    public:
        virtual ~IHandler() {}
        void SetNextHandler(IHandler *next) { // 链表关系
            next = next;
        }
        // 抽象稳定点,对扩展开放
        // 模板模式:固定算法骨架,通过子类去扩展子流程
        bool Handle(const Context &ctx) {
            if (CanHandle(ctx)) {
                return HandleRequest(ctx);
            } else if (GetNextHandler()) {
                return GetNextHandler()->Handle(ctx);
            } else {
                // err
            }
            return false;
        }
    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){
            //
            return true;
        }
        virtual bool CanHandle(const Context &ctx) {
            //
            if (ctx.day <= 10)
                return true;
            return false;
        }
    };
    
    class HandleByProjMgr : public IHandler {
    protected:
        virtual bool HandleRequest(const Context &ctx){
            //
            return true;
        }
        virtual bool CanHandle(const Context &ctx) {
            //
            if (ctx.day <= 20)
                return true;
            return false;
        }
    };
    class HandleByBoss : public IHandler {
    protected:
        virtual bool HandleRequest(const Context &ctx){
            //
            return true;
        }
        virtual bool CanHandle(const Context &ctx) {
            //
            if (ctx.day < 30)
                return true;
            return false;
        }
    };
    
    //秘书处理
    class HandleByBeauty : public IHandler {
    protected:
        virtual bool HandleRequest(const Context &ctx){
            //
            return true;
        }
        virtual bool CanHandle(const Context &ctx) {
            //
            if (ctx.day <= 3)
                return true;
            return false;
        }
    };
    
    int main() {
    // 可以用抽象工厂优化
    // nginx http 处理 
        IHandler * h0 = new HandleByBeauty();
        IHandler * h1 = new HandleByMainProgram();
        IHandler * h2 = new HandleByProjMgr();
        IHandler * h3 = new HandleByBoss();
        h0->SetNextHandler(h1);
        h1->SetNextHandler(h2);
        h2->SetNextHandler(h3);
        // 设置下一指针 
        Context ctx;
        h0->Handle(ctx);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    装饰器

    定义

    动态的给一个对象增加一些额外的职责,就增加功能来说,装饰器模式比生产子类更加灵活。

    例子

    普通员工有销售奖金,累计奖金,部门经理除此之外还有团队奖金;后面可能会添加环比增长奖
    金,同时可能针对不同的职位产生不同的奖金组合;

    在这里插入图片描述

    稳定点: 增加奖金的规则

    变化点:员工类型;不同奖金的组合

    要点
    • 通过组合而非继承的方法,装饰器模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的 灵活性差多子类衍生问题。
    • 不是解决 多子类衍生问题 ,而是解决 父类在多个方向上扩展功能的问题
    • 装饰器模式把一系列复杂的功能分散到每个装饰器中,一般一个装饰器只实现一个功能,实现复用装饰器的功能。
    本质

    动态组合

    示例代码
    class Context {
    public:
        bool isMgr;
        // User user;
        // double groupsale;
    };
    
    
    class CalcBonus {    
    public:
        CalcBonus(CalcBonus * c = nullptr) : cc(c) {}
        virtual double Calc(Context &ctx) {
            return 0.0; // 基本工资
        }
        virtual ~CalcBonus() {}
    
    protected:
        CalcBonus* cc; //组合的方式
    };
    
    class CalcMonthBonus : public CalcBonus {
    public:
        CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}
        virtual double Calc(Context &ctx) {
            double mbonus /*= 计算流程忽略*/; 
            return mbonus + cc->Calc(ctx);
        }
    };
    
    class CalcSumBonus : public CalcBonus {
    public:
        CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}
        virtual double Calc(Context &ctx) {
            double sbonus /*= 计算流程忽略*/; 
            return sbonus + cc->Calc(ctx);
        }
    };
    
    class CalcGroupBonus : public CalcBonus {
    public:
        CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}
        virtual double Calc(Context &ctx) {
            double gbnonus /*= 计算流程忽略*/; 
            return gbnonus + cc->Calc(ctx);
        }
    };
    
    class CalcCycleBonus : public CalcBonus {
    public:
        CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}
        virtual double Calc(Context &ctx) {
            double gbnonus /*= 计算流程忽略*/; 
            return gbnonus + cc->Calc(ctx);
        }
    };
    
    int main() {
    
        //装饰器(decorator)这类似于是一个[功能链],要与责任链区分一下
        //责任链强调顺序,且有打断功能
        //装饰器与顺序无关
        // 1. 普通员工
        Context ctx1;
        CalcBonus *base = new CalcBonus();
        CalcBonus *cb2 = new CalcSumBonus(base);
        CalcBonus *cb1 = new CalcMonthBonus(cb2);
    
    
        cb2->Calc(ctx1); //计算只包含SumBonus的员工ctx1的奖金数
        // 2. 部门经理
        Context ctx2;
        CalcBonus *cb3 = new CalcGroupBonus(cb2);
        //计算包含所有奖金的雇员ctx2的总奖金
        cb3->Calc(ctx2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    问题

    1. 抽象工厂再理解
  • 相关阅读:
    【Web前端大作业】基于HTML+CSS+JavaScript制作西北大学新闻网站(7页)
    16位 (MCU) R7F101G6G3CSP、R7F101G6E3CSP、R7F101G6G2DSP、R7F101G6E2DSP是新一代RL78通用微控制器
    解析Redis缓存穿透、击穿和雪崩问题及解决方案
    使用Django JWT实现身份验证
    简单选择排序
    HTML入门(3)——一个简单的HTML5文档
    只要15分钟,轻松get费用报销系统
    Golang JWT 认证 (一)- 后端
    ElasticSearch第二讲:ES详解 - ElasticSearch基础概念
    arcgis 生成切片并发布服务
  • 原文地址:https://blog.csdn.net/qq_42120843/article/details/126824851