23种设计模式之C++实践

23种设计模式之C++实践

  • 1. 简介
  • 2. 基础知识
  • 3. 设计模式
    • (一)创建型模式
      • 1. 单例模式
        • 1.2 饿汉式单例模式
        • 1.3 懒汉式单例模式
        • 比较
        • IoDH
        • 单例模式总结
      • 2. 简单工厂模式
        • 简单工厂模式总结
      • 3. 工厂方法模式
        • 工厂方法模式总结
      • 4. 抽象工厂模式
        • 抽象工厂模式总结
      • 5. 原型模式
        • 原型模式总结
      • 6. 建造者模式
        • 建造者模式总结

1. 简介

设计模式是一门技术,更是一门艺术,它为构建可维护性和可复用性俱佳的软件而诞生。

2. 基础知识

  1. 设计模式(Design Pattern):是一套被反复使用的,多数人知晓的,经过分类编目的代码设计经验的总结,使用设计模式是为了可以重用代码,让代码更容易被理解提高代码的可靠性
  2. UML(United Modeling Language)
      1. 关联关系(实线):通常将一个类的对象作为另一个类的成员变量。
        1. 双向关联
        2. 单向关联
        3. 自关联
        4. 多重性关联
      2. 聚合关系(空心菱形直线):成员是整体的一部分,但是成员可以脱离整体存在。通常通过set()函数初始化成员变量。
      3. 组合关系(实心菱形直线):整体控制成员的声明周期,整体不存在,则成员不存在。通常通过构造函数初始化成员变量。
      4. 依赖关系(带箭头虚线):类的改变影响到使用该类的其他类,则其他类依赖该类。通常通过将一个类的对象作为另一个类中方法的参数体现。
      5. 泛化关系/继承关系(空心三角形实线):父类与子类。
      6. 接口与实现关系(空心三角形虚线):在接口类中声明抽象函数,在实现类中实现函数。
  3. 面向对象设计原则
    1. 单一职责原则(Single Responsibility):一个类只负责一个功能领域中的相应职责。或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。高内聚,低耦合
    2. 开闭原则(Open-Closed Principle,OCP):一个软件实体应该对外扩展开放,对修改关闭。即软件实体尽量在不修改原有代码的基础下进行扩展。抽象化
    3. 里氏代换原则(Liskov Substitution Principle,LSP):所有引用父类的地方必须能透明地使用其子类的对象。父类抽象化
    4. 依赖倒转原则(Dependency Inversion Principle,DIP):抽象不应该依赖于细节,细节应该依赖于抽象。即针对接口编程,而不是针对实现编程。参数抽象化
    5. 接口隔离原则(Interface Segregation Principle,ISP):使用多个专用的接口,而不适用单一的总接口,即客户端不应该依赖那些它不需要的接口。
    6. 合成复用原则(Composite Reuse Principle,CRP):尽量使用对象组合,而不是继承来达到复用的目的。
    7. 迪米特法则/最少知识原则(Law of Demeter/Least Knowledge Principle,LoD/LKP):一个软件实体应该尽可能少的与其他实体发生相互作用。

3. 设计模式

(一)创建型模式

1. 单例模式

  1. 单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类成为单例类,它提供全局访问的方法。

  2. 要点:

    1. 某个类只能有一个实例

    2. 它必须自行创建这个实例

    3. 它必须自行向整个系统提供这个实例

  3. 结构图:

  4. 使用场景实例

    Windows任务管理器

    在一个Windows系统中,任务管理器存在唯一性。

  5. 代码实例

    // TaskManager.h
    class TaskManager {
         
     private:
      /**
       * @brief 初始化窗口
       *
       */
      TaskManager() {
         }
    
     public:
      /**
       * @brief 显示进程
          *
          */
    
        void displayProcesses();
    
      /**
       * @brief 显示服务
          *
          */
    
        void displayServices();
    
     private:
      static TaskManager* tm;
    
     public:
      static TaskManager* getInstance();
    };
    
    // TaskManager.cpp
    TaskManager* TaskManager::tm = nullptr;
    
    void TaskManager::displayProcesses() {
         
      printf("显示进程……\n");
      return;
    }
    void TaskManager::displayServices() {
         
      printf("显示服务……\n");
      return;
    }
    
    TaskManager* TaskManager::getInstance() {
         
      if (tm == nullptr) {
         
        tm = new TaskManager();
      }
      return tm;
    }
    
  6. 代码测试

    • 测试代码:

      int main(int argc, char** argv) {
             
        printf("I'm Singleton Pattern!\n");
        // begin test
        SingleTonNS::TaskManager* tm = SingleTonNS::TaskManager::getInstance();
        tm->displayProcesses();
        tm->displayServices();
        // end test
        return 0;
      }
      
    • 输出

      I’m Singleton Pattern!
      显示进程……
      显示服务……

1.2 饿汉式单例模式
  1. 饿汉式单例模式(Eager Singleton):在定义静态变量的时候实例化单例类,因此在类加载时就已经创建了单例对象

  2. 结构图

  3. 代码示例

     // TaskManager.h
     class TaskManager {
         
      private:
       /**
        * @brief 初始化窗口
        *
        */
       TaskManager() {
         }
    
      public:
       /**
        * @brief 显示进程
           *
           */
    
         void displayProcesses();
    
       /**
        * @brief 显示服务
           *
           */
    
         void displayServices();
    
      private:
       static TaskManager* tm;
    
      public:
       static TaskManager* getInstance();
     };
    
     // TaskManager.cpp
     // 饿汉式单例模式初始化
     TaskManager* TaskManager::tm = new TaskManager();
    
     void TaskManager::displayProcesses() {
         
       printf("显示进程……\n");
       return;
     }
     void TaskManager::displayServices() {
         
       printf("显示服务……\n");
       return;
     }
     TaskManager* TaskManager::getInstance() {
         
       return tm;
     }
    
1.3 懒汉式单例模式
  1. 见单例模式实现方式。
比较
  1. 饿汉式单例类

    • 优点

      1. 无需考虑多线程访问问题,可以确保实例的唯一性

      2. 调用速度与反应时间更快

    • 缺点

      1. 资源利用效率更低

      2. 加载时间更长

  2. 懒汉式单例类

    • 优点
      1. 延迟加载,无需一直占用系统资源
    • 缺点
      1. 必须处理好多线程同时访问的问题,可能引起性能受影响
IoDH
  1. 有没有一种方法,能够将两种单例的缺点都克服,而将两者的优点合二为一呢?答案是肯定的,即Initialization on Demand Holder技术
  2. IoDH:在单例类中增加一个静态内部类,在该内部类中,创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用。
  3. 使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能,但是与编程语言本身的特性相关,很多面向对象语言不支持IoDH,例如C++。支持的语言有Java。
单例模式总结
  • 优点
    1. 提供了对唯一实例的受控访问。
    2. 节约系统资源
    3. 允许可变数目的实例。
  • 缺点
    1. 没有抽象层,扩展较为困难
    2. 职责过重,一定程度上违反了单一职责原则。
    3. 很多面向对象语言(例如Java,C#)的运行环境都提供了自动垃圾回收技术,因此,如果实例化的共享对象长期不被利用,会自动销毁并回收资源,下次利用时重新实例化,这将导致共享的单例对象状态的丢失。
  • 适用场景
    1. 系统只需要一个实例对象
    2. 客户调用类的单个实例只允许使用一个公共访问点。

2. 简单工厂模式

  1. 简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建类的实例通常具有共同的父类。

  2. 要点:

    1. 当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
  3. 结构图:

  4. 适用场景实例

    图标库:为应用系统提供各种不同外观的图表,例如柱状图、饼状图、折线图等等

  5. 代码示例

// Chart.h
/**
 * @brief 图表类接口
 *
 */
class Chart {
   
 public:
  virtual void display() = 0;
};

/**
 * @brief 柱状图
 *
 */
class HistogramChart : public Chart {
   
 public:
  HistogramChart();
  void display() override;
};

/**
 * @brief 饼状图
 *
 */
class PieChart : public Chart {
   
 public:
  PieChart();
  void display() override;
};

/**
 * @brief 折线图
 *
 */
class LineChart : public Chart {
   
 public:
  LineChart();
  void display() override;
};

// ChartFactory.h
class ChartFactory {
   
 public:
  static Chart* getChart(std::string type);
};

// Chart.cpp
HistogramChart::HistogramChart() {
    printf("创建柱状图!\n"); }

void HistogramChart::display() {
   
  printf("展示柱状图!\n");
  return;
}

PieChart::PieChart() {
    printf("创建饼状图!\n"); }

void PieChart::display(

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/197596.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Django大回顾-2 之 Django的基本操作、路由层,MTV和MVC模型

【1】MTV和MVC模型 MVC与MTV模型 --->所有web框架其实都遵循mvc架构 MVC模型 MVC 本来坨在一起的代码,拆到不同的位置 模型(M:数据层),控制器(C:逻辑判断)和视图(V:用户看到的)三层 他们之间以一种插件式…

C++ 背包理论基础01 + 滚动数组

背包问题的重中之重是01背包 01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 每一件物品其实只有两个状态,取或者不…

sprintboot快速初始化【Springboot】

1.首先选择创建项目 2.填写对应的项目信息 一定要勾选maven,否则没有pom文件,选择next 3.选择应用场景 点击 create,DIEA就会根据你的选择自动创建项目骨架; 4.创建一个控制层 随便创建一个控制层,测试一下项目是否…

智能优化算法应用:基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阴阳对算法4.实验参数设定5.算法结果6.参考文献7.…

js相同字符串截取拼接

原数据 const list [999-1234567801,999-1234567802,999-1234567803, ]; const list1 [999-1234567899,999-1234567900,999-1234567901, ];期望数据 999-1234567801/2/3 //list 999-1234567899/900/901 //list1处理代码 // 连续号码处理 export const formatNumber (tick…

Python实现性能自动化测试

一、思考❓❔ 1.什么是性能自动化测试? 性能 系统负载能力超负荷运行下的稳定性系统瓶颈自动化测试 使用程序代替手工提升测试效率性能自动化 使用代码模拟大批量用户让用户并发请求多页面多用户并发请求采集参数,统计系统负载能力生成报告 2.Python中的性能自动…

Python 装饰器与偏函数

目录 装饰器 概念 简单的装饰器 复杂点的装饰器 通用装饰器 定义通用装饰器 使用装饰器 偏函数 引入类库 应用 总结 装饰器 概念 装饰器就是个闭包;把一个函数当做参数,返回一个修改过功能的函数; 本质上是一个返回函数的函数。…

堆排序(详解)

在上篇文章中,我们说利用堆的插入和删除也可以排序数据,但排序的只是堆里面的数组;同时每次排序数据都要单独写一个堆的实现,很不方便,这次就来着重讲讲如何使用堆排序。 1.建堆 给了你数据,要利用堆对数据…

echarts修改tooltip默认的圆点图标为其他样式

业务需求,默认是圆点,需要把线的由圆点改为线 红色线是理论,点是历史理论,绿色线是实际, 点是历史实际,在series里的顺序也是这样排的。 打印出来的params里的marker就是圆点,改这段代码就可以了…

C#面向对象

过程类似函数只能执行没有返回值 函数不仅能执行,还可以返回结果 1、面向过程 a 把完成某一需求的所有步骤 从头到尾 逐步实现 b 根据开发需求,将某些 功能独立 的代码 封装 成一个又一个 函数 c 最后完成的代码就是顺序的调用不同的函数 特点 1、…

vue项目多个不同的服务器请求地址管理

vue项目多个不同的服务器请求地址管理 在vue项目开发过程中,获取不同的数据可能会出现需要请求多个不同服务器地址的域名,这个时候需要对不同域名的请求地址进行管理以及跨域的代理。 一、单服务器域名地址的跨域代理和请求配置: 跨域配置: 在vue项目的vue.config.js文件…

MYSQL 8.X Linux-Generic 通用版本安装

下载对应版本MySQL :: Download MySQL Community Server (Archived Versions) 这里我选择的是Linux - Generic (glibc 2.12) (x86, 64-bit), TAR 解压到服务器 只需要里面的mysql-8.0.24-linux-glibc2.12-x86_64.tar.xz 在目录下创建需要的文件夹 这里我改名为mysql-8.0.24…

贪心算法(新坑)

贪心入门 概述: 贪心算法是一种在每一步选择中都采取当前最优解的策略,希望最终能够得到全局最优解的算法。简单来说,它会不断地做出局部最优的选择,相信通过这种选择最终能够达到全局最优。 举个例子来说明。假设你要从一个迷…

智能优化算法应用:基于回溯搜索算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于回溯搜索算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于回溯搜索算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.回溯搜索算法4.实验参数设定5.算法结果6.参考…

fiddler测试弱网别再去深山老林测了,这样做就能达到弱网效果了!

弱网测试 概念:弱网看字面意思就是网络比较弱,我们通称为信号差,网速慢。 意义:模拟在地铁、隧道、电梯和车库等场景下使用APP ,网络会出现延时、中断和超时等情况。 添加图片注释,不超过 140 字&#xf…

【双指针】三数之和

三数之和 在做这道题之前,建议建议先将两数之和做完再做,提升更大~ 文章目录 三数之和题目描述算法原理解法一解法二思路如下:处理细节问题: 代码编写Java代码编写C代码编写 15. 三数之和 - 力扣(LeetCode&#xff0…

AIGC文生图及工具产品简介

AIGC,全称是人工智能生成内容(Artificial Intelligence Generated Content)是继UGC(用户生成内容),PGC(平台生成内容)后,利用人工智能技术,自动生成内容的生产…

C++初阶--String类的使用

string类 在C语言中,我们总是用char* 的类型来创建一个变量,存储一个字符串;当我们想对它进行修改或者读写时,需要自我创建空间和使用string.h的库函数来进行操作它; 而在C中,C专门提供了一个头文件 stri…

Vue2问题:如何全局使用less和sass变量?

前端功能问题系列文章,点击上方合集↑ 序言 大家好,我是大澈! 本文约2400字,整篇阅读大约需要4分钟。 本文主要内容分三部分,如果您只需要解决问题,请阅读第一、二部分即可。如果您有更多时间&#xff…

KernelSHAP vs TreeSHAP

Kernel SHAP和Tree SHAP都用于近似Shapley值。Tree SHAP要快得多。缺点是它只能用于基于树的算法,如随机森林和xgboost。另一方面,Kernel SHAP是模型不可知的(model agnostic),这意味着它可以与任何机器学习算法一起使用。我们将比较这两种近…