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")

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

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

相关文章

TOP-K问题和向上调整算法和向下调整算法的时间复杂度问题的分析

TOP-K问题 TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大 比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等 对于Top-K问题,能想到的最简单直接的方式就是排序,但是…

LD_PRELOAD劫持、ngixn临时文件、无需临时文件rce

LD_PRELOAD劫持 <1> LD_PRELOAD简介 LD_PRELOAD 是linux下的一个环境变量。用于动态链接库的加载&#xff0c;在动态链接库的过程中他的优先级是最高的。类似于 .user.ini 中的 auto_prepend_file&#xff0c;那么我们就可以在自己定义的动态链接库中装入恶意函数。 也…

maven下载和安装

maven下载和安装 一、概述 Maven是一个项目管理工具&#xff0c;它包含了一个项目对象模型 (Project Object Model)&#xff0c;一组标准集合&#xff0c;一个项目生命周期(Project Lifecycle)&#xff0c;一个依赖管理系统(Dependency Management System)&#xff0c;和用来…

算法通关村第十四关-白银挑战堆的经典问题

大家好我是苏麟 , 今天带来堆的一些经典问题 , 我们一起研究一下 . 大纲 数组中的第K个最大元素合并 K 个升序链表 数组中的第K个最大元素 描述 : 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k …

Hdoop学习笔记(HDP)-Part.14 安装YARN+MR

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Java Throwable

如图展示了 Java 整个异常体系的关系。 Throwable 的 Java 异常体系的基类, 他的直接子类有 Error 和 Exception 2 个。 1 Error Error 表示的是由于系统错误, Java 虚拟机抛出的异常, 例如 Java 虚拟机崩溃, 内存不够等, 这种情况仅凭程序自身是无法处理的, 在程序中也不会…

VBA_MF系列技术资料1-232

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

Aspice(Automotive Software Process Improvement and Capability Determination)

Aspice&#xff08;Automotive Software Process Improvement and Capability Determination&#xff09; 1. 引言&#xff1a;ASPICE概述 定义 ASPICE简介&#xff1a;ASPICE&#xff08;Automotive Software Process Improvement and Capability Determination&#xff09;…

使用coco数据集进行语义分割(1):数据预处理,制作ground truth

如何coco数据集进行目标检测的介绍已经有很多了&#xff0c;但是关于语义分割几乎没有。本文旨在说明如何处理 stuff_train2017.json stuff_val2017.json panoptic_train2017.json panoptic_val2017.json&#xff0c;将上面那些json中的dict转化为图片的label mask&am…

前几天面了个30岁的测试员,年薪50w问题基本都能回答上,应该刷了不少八股文···

互联网行业竞争是一年比一年严峻&#xff0c;作为测试工程师的我们唯有不停地学习&#xff0c;不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水&#xff0c;进入心仪的企业&#xff08;阿里、字节、美团、腾讯等大厂.....&#xff09; 所以&#xff0c;大家就迎来了…

【每日一题】拼车+【差分数组】

文章目录 Tag题目来源解题思路方法一&#xff1a;差分 写在最后 Tag 【差分数组】【数组】【2023-12-02】 题目来源 1094. 拼车 解题思路 本题朴素的解题思路是统计题目中提到的每一个站点的车上人数&#xff0c;如果某个站点的车上人数大于车上的座位数直接返回 false&…

1688API接口系列,1688开放平台接口使用方案(商品详情数据+搜索商品列表+商家订单类)

1688商品详情接口是指1688平台提供的API接口&#xff0c;用于获取商品详情信息。通过该接口&#xff0c;您可以获取到商品的详细信息&#xff0c;包括商品标题、价格、库存、描述、图片等。 要使用1688商品详情接口&#xff0c;您需要先申请1688的API权限&#xff0c;并获取ac…

java八股文

1线程池中提交一个任务得流程是怎样的 源代码 public void execute(Runnable command) {if (command null)throw new NullPointerException();/** Proceed in 3 steps:** 1. If fewer than corePoolSize threads are running, try to* start a new thread with the given comm…

vivado实现分析与收敛技巧5-增量流程中的 RQS

当设计非常接近时序收敛 &#xff08; 通常 WNS 小于 -250 ps &#xff09; 时 &#xff0c; 可启用增量流程并包含 RQS 建议。这样即可利用增量流程和RQS 建议来实现时序收敛并节省迭代时间。 report_qor_assessment 用于在“ Flow Guidance ” &#xff08; 流程指南 &…

树莓派4b安装ubuntu22和向日葵设置开机启动

树莓派4b安装ubuntu22和向日葵设置开机启动 使用树莓派烧录系统工具烧录ubuntu 在树莓派官网下载官方软件&#xff0c;安装完后运行 在软件上选择 选择ubuntu桌面或者server 根据自己需求选择&#xff0c;这里我选择22.04的系统 烧录好以后进入系统 安装向日葵 下载树莓…

同旺科技 USB TO SPI / I2C --- 调试W5500

所需设备&#xff1a; 内附链接 1、USB转SPI_I2C适配器(专业版); 首先&#xff0c;连接W5500模块与同旺科技USB TO SPI / I2C适配器&#xff0c;如下图&#xff1a; 读取重试时间值寄存器&#xff0c;默认值0x07D0 输出结果与默认值一致&#xff0c;芯片基本功能已经调通&am…

代码随想录算法训练营第39天| 62.不同路径 63. 不同路径 II

JAVA代码编写 62.不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不…

锐捷EWEB网管系统 RCE漏洞复现

0x01 产品简介 锐捷网管系统是由北京锐捷数据时代科技有限公司开发的新一代基于云的网络管理软件&#xff0c;以“数据时代创新网管与信息安全”为口号&#xff0c;定位于终端安全、IT运营及企业服务化管理统一解决方案。 0x02 漏洞概述 Ruijie-EWEB 网管系统 flwo.control.ph…

吸烟(抽烟)检测和识别2:Pytorch实现吸烟(抽烟)检测和识别(含吸烟(抽烟)数据集和训练代码)

吸烟(抽烟)检测和识别2&#xff1a;Pytorch实现吸烟(抽烟)检测和识别(含吸烟(抽烟)数据集和训练代码) 目录 吸烟(抽烟)检测和识别2&#xff1a;Pytorch实现吸烟(抽烟)检测和识别(含吸烟(抽烟)数据集和训练代码) 1.吸烟(抽烟)检测和识别 2.吸烟(抽烟)数据集 &#xff08;1&am…

深度学习 -- 卷积神经网络

1、卷积神经网络的结构 大卫休伯尔( David Hunter Hubel ) 等人研究发现&#xff0c;猫的视皮层上 存在简单细胞( simple cell )和复杂细胞( complex cell )&#xff0c;简单细胞会对 感受野中特定朝向的线段做出反应&#xff0c;而复杂细胞对于特定朝向的钱段移动也能做出反应…