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

1.2.2 结构型设计模式

Posted on 2023-04-01 23:07  wsg_blog  阅读(10)  评论(0编辑  收藏  举报

Linux C/C++服务器

结构型设计模式

结构型设计模式

单例模式

保证一个类仅有一个实例,并提供一个该实例的全局访问点。——《设计模式》GoF
单例模式的对象通常和应用程序的生命周期是一模一样的,对于用户而言,我们不希望用户去new它或者delete它,因此我们需要对用户隐藏它的构造和析构函数(private),我们应用程序退出的时候才会去释放它
链接中还给出了多个版本的单例代码,感兴趣的可以去看下

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

工厂模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。 ——《设计模式》GoF
设计原则:最小知道原则、面向接口编程
应用:实现导出数据的接口, 导出数据的格式包含 xml,json,文本格式txt 后面可能扩展excel格式csv

#include <string>
// 实现导出数据的接口, 导出数据的格式包含 xml,json,后面可能扩展excel格式csv文本格式txt
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 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;
    }
};

int main () {
    IExportFactory *factory = new ExportJsonFactory();
    factory->Export("hello world");
    return 0;
}

抽象工厂

提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。 ——《设计模式》GoF
抽象工厂和工厂类比较类似,区别为同类对象有 多个 相同的职责


责任链

本质:分离职责,动态组合;

定义

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

背景

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

要点

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

装饰器

本质:动态组合

定义

动态地给一个对象增加一些额外的职责。就增加功能而言,装饰器模式比生产子类更为灵活。 —— 《设计模式》GoF

背景

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

要点

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

什么时候使用?

不影响其他对象的情况下,以动态、透明的方式给对象添加职责;每个职责都是完全独立的功能,彼此之间没有依赖

组合模式

将对象组合成树型结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

什么时候使用组合模式?

  • 如果你想表示对象的部分-整体层次结构,可以选用组合模式,把整体和部分的操作统一起来,使得层次结构实现更简单,从外部来使用这个层次结构也容易;
  • 如果你希望统一地使用组合结构中的所有对象,可以选用组合模式,这正是组合模式提供的主要功能;