C++ 设计模式

文章目录

  • 类图
    • 泛化
    • 实现
    • 关联
    • 聚合
    • 组合
    • 依赖
    • 总结
  • 类内部的三种权限(公有、保护、私有)
  • 类的三种继承方式
    • 描述与图
    • 总结
  • 面向对象七大原则
    • 单一职责原则(Single Responsibility Principle)
    • 里氏替换原则(Liskov Substitution Principle)
    • 依赖倒置原则(Dependence Inversion Principle)
    • 接口隔离原则(Interface Segregation Principle)
    • 迪米特法则(Law Of Demeter)
    • 开闭原则(Open Close Principle)
    • 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
  • 关于类的静态成员
  • 关于C++构造函数的继承问题
  • 创建型模式
    • Factory模式(工厂模式)
    • AbstractFactory模式(抽象工厂模式)

类图

泛化

  • 【泛化】是一种继承关系,表示一般与特殊的关系,它指定了子类如何继承父类的所有特征和行为。例如:老虎是动物的一种,即有老虎的特性也有动物的共性。
  • 【代码体现】:继承。
  • 特征:空白三角形+实线 指向父类
    动物是老虎的父类

实现

  • 【实现关系】是一种类与接口的关系,表示类是接口所有特征和行为的实现。

  • 特征:空白三角形箭头+虚线 箭头指向接口
    在这里插入图片描述

  • 【代码体现】:纯虚函数

  • 对于C++,其接口类一般具有以下特征:

    • 最好不要有成员变量,但可以有静态常量(static const或enum)
      • 如果成员变量,尤其是可变的成员变量,定义在接口中,等于是把实现细节暴露出来了,不符合接口定义的要求,所以一般不在接口中定义可变的成员变量。
        而常量可以定义在接口中,因为有时接口需要返回状态,而这些状态可以定义成常量放在接口中。
    • 要有纯虚接口方法
      • 由于不能让接口类自身能够实例化,并且需要子类必须实现接口暴露的方法,所以接口方法都要声明成纯虚函数。
        声明成纯虚函数意味着接口类自身不需要提供方法的定义,方法的定义需要由接口类的子类提供,并且接口类自身也因此变成了抽象类而不能被实例化。
    • 要有虚析构函数,并提供默认实现
      • 在使用接口类的指针访问接口类的子类的实例时,当对接口类的指针做delete时,如果接口类的析构函数不是虚析构函数的话,将只会调用接口类(父类)的析构函数,接口类的子类的析构函数将不会被调用,内存泄露将会产生,所以接口类的析构函数必须定义成虚析构函数。
      • 如果接口类的析构函数不提供默认实现,即如果接口类的析构函数是纯虚析构函数的话,接口类的子类将被迫必须提供析构函数的实现,这样对接口类的子类不友好。
    • 不要声明构造函数
      • 不要显式定义任何的构造函数,但也不要在接口中加入如下代码来禁止生成构造函数:
      • Testable() = delete; Testable(const Testable&) = delete;
      • 因为C++的调用机制要求子类的构造函数调用时一定会先调用父类的构造函数,如果禁止生成父类构造函数,代码编译时会报错。如果程序员不显式的提供构造函数,编译器也会隐式的加上构造函数的,虽然这些构造函数对于接口类来说实际没有什么意义。
    • 例子:
class Testable
{
public:static const int START = 1;  // #1static const int STOP = 2;virtual void test() = 0;  // #2: 接口方法virtual ~Testable() {};   // #3: 从C++11开始可以: virtual ~Testable() = default;
}

关联

  • 【关联关系】是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
  • 【代码体现】:成员变量
  • 特征:实线 n n实线 1 n 箭头指向被拥有者
    在这里插入图片描述
  • 上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西他不拥有学生。

聚合

  • 【聚合关系】:是整体与部分的关系,且部分可以离开整体而单独存在。如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。
  • 【聚合关系】是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
  • 特征:菱形+实线+箭头在这里插入图片描述

组合

  • 【组合关系】:是整体与部分的关系,但部分不能离开整体而单独存在。如公司和部门是整体和部分的关系,没有公司就不存在部门

  • 组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。
    在这里插入图片描述

依赖

  • 【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖.
  • 【代码表现】:局部变量、方法的参数、对静态方法的调用、函数返回值
  • 【箭头及指向】:带箭头的虚线,指向被使用者。
    在这里插入图片描述

总结

各种关系的强弱顺序:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖
下面这张UML图,比较形象地展示了各种类图关系:
在这里插入图片描述

类内部的三种权限(公有、保护、私有)

在这里插入图片描述
权限按照以下两点递减:

  • 是否能被外部访问
  • 是否能被继承的子类访问

类的三种继承方式

描述与图

  • public继承方式
    基类中所有 public 成员在派生类中为 public 属性;
    基类中所有 protected 成员在派生类中为 protected 属性;
    基类中所有 private 成员在派生类中不能使用。

  • protected继承方式
    基类中的所有 public 成员在派生类中为 protected 属性;
    基类中的所有 protected 成员在派生类中为 protected 属性;
    基类中的所有 private 成员在派生类中不能使用。

  • private继承方式
    基类中的所有 public 成员在派生类中均为 private 属性
    基类中的所有 protected 成员在派生类中均为 private 属性
    基类中的所有 private 成员在派生类中不能使用。

继承方式/基类成员public成员protected成员private成员
public继承publicprotected不可见
protected继承protectedprotected不可见
private继承privateprivate不可见

总结

  • 父类的private成员在子类不能使用、不可见
  • 父类的成员在子类中的权限,最高为其子类的继承方式。

面向对象七大原则

单一职责原则(Single Responsibility Principle)

  • 每一个类应该专注于做一件事情
  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;提高类的可读性,提高系统的可维护性;变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

里氏替换原则(Liskov Substitution Principle)

  • 子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏
  • 使用里氏替换原则时需要注意,子类的所有方法必须在父类中声明,或子类必须实现父类中声明的所有方法。尽量把父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。

依赖倒置原则(Dependence Inversion Principle)

  • 程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
  • 面向抽象编程,也就是面向抽象类或接口编程。

接口隔离原则(Interface Segregation Principle)

应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

迪米特法则(Law Of Demeter)

又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

开闭原则(Open Close Principle)

面向扩展开放,面向修改关闭。

组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)

尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。

关于类的静态成员

  • 类的静态成员与类本身直接相关而不是与类的各个对象保持关联

  • 我们不能在类的内部初始化静态数据成员必须在类的外部初始化
    在这里插入图片描述
    在这里插入图片描述

  • 字面值常量类型constexpr除外
    在这里插入图片描述

关于C++构造函数的继承问题

  • 构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,子类需要调用其父类的构造方法
  • 如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建
  • 如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式
#include <iostream.h>  class animal  {  public:  animal(int height, int weight)   //有且仅有 有参参数,必须显性调用{  cout<<"animal construct"<<endl;  }};  class fish:public animal  {  public:  fish():animal(400,300)  {  cout<<"fish construct"<<endl;  }};  void main()  {  fish fh;  }  
  • 在fish类的构造函数后,加一个冒号(:),然后加上父类的带参数的构造函数。这样,在子类的构造函数被调用时,子类就会去调用父类的带参数的构造函数去构造对象

创建型模式

Factory模式(工厂模式)

在这里插入图片描述

//Product.h
#ifndef _PRODUCT_H_
#define _PRODUCT_H_
class Product
{
public:virtual ~Product() = 0; //多态时,调用子类的析构函数
protected:Product();     //不可被外部调用,抽象基类不可以被实例化
private:
};class ConcreteProduct:public Product
{
public:~ConcreteProduct();ConcreteProduct();
protected:
private:
};
#endif
//Product.cpp
#include "Product.h"
#include <iostream>
Product::Product()
{std::cout<<"Product()...."<<std::endl; 
}Product::~Product()
{std::cout<<"~Product()...."<<std::endl; 
}ConcreteProduct::ConcreteProduct()
{std::cout<<"ConcreteProduct()...."<<std::endl; 
}ConcreteProduct::~ConcreteProduct()
{std::cout<<"~ConcreteProduct()...."<<std::endl; 
}
//Factory.h
#ifndef _FACTORY_H_
#define _FACTORY_H_
class Product;
//factory抽象基类
class Factory   
{
public:virtual ~Factory() = 0;         //析构函數virtual Product* CreateProduct() = 0;   
protected:Factory();      //构造函数,外部不可以调用,子类可以调用
private:
};//factory实例
class ConcreteFactory:public Factory
{
public:~ConcreteFactory();         ConcreteFactory();Product* CreateProduct();
protected:
private:
};
#endif
//Factory.cpp
#include "Product.h"
#include "Factory.h"
#include <iostream>Factory::Factory()
{std::cout<<"Factory()...."<<std::endl; 
}Factory::~Factory()
{std::cout<<"~Factory()...."<<std::endl; 
}ConcreteFactory::ConcreteFactory()
{std::cout<<"ConcreteFactory()......"<<std::endl;
}ConcreteFactory::~ConcreteFactory()
{std::cout<<"~ConcreteFactory()......"<<std::endl;
}Product* ConcreteFactory::CreateProduct()
{return new ConcreteProduct();
}
//main.cpp
#include "Factory.h"
#include "Product.h"
#include <iostream>
#include <cstdio>
int main(int argc, char* argv[])
{Factory *fac = new ConcreteFactory();Product* p = fac->CreateProduct();delete p;delete fac;return 0;
}
#makefile
CC = g++ -g
BaseIncludePath = ../include/
SRCS = main.cpp Product.cpp Factory.cpp
OBJS = $(addsuffix .o,$(basename ${SRCS}))main.exe: $(OBJS)$(CC) $(OBJS) -o main.exe %.o: %.cpp$(CC) -c $< -o $@ -I$(BaseIncludePath)clean:del $(OBJS) main.exe

AbstractFactory模式(抽象工厂模式)

在这里插入图片描述

  • 抽象工厂模式和工厂方法模式一样,都符合开闭原则。但是不同的是,在抽象工厂模式中,增加一个产品族很容易,而增加一个产品等级结构却很难,工厂模式则反之。

  • 也就是说,在抽象工厂模式中,增加一个具体的工厂很容易,但是你想在工厂中多生产一种产品,就需要修改很多个类,会违背开闭原则,这种情况下应该使用工厂模式。

  • 简单来说:工厂模式新增产品类型容易,抽象工厂模式新增工厂类型容易

表头表头
单元格单元格
单元格单元格

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python is not set from command line or npm configuration 报错解决

问题 在 npm install 的过程中提示 Python is not set from command line or npm configuration 的报错&#xff0c;相信不少朋友都遇到过&#xff0c;出现这个问题的原因是缺少 python 环境所导致的。 解决方法 1、安装 python 官网&#xff1a;https://www.python.org/dow…

DVWA 靶场 SQL 注入报错 Illegal mix of collations for operation ‘UNION‘ 的解决方案

在 dvwa 靶场进行联合 SQL 注入时&#xff0c;遇到报错 Illegal mix of collations for operation UNION 报错如下图&#xff1a; 解决办法&#xff1a; 找到文件 MySQL.php 大致位置在 \dvwa\includes\DBMS 目录下 使用编辑器打开 检索 $create_db 第一个就是 在 {$_DVW…

android开发电子书,android基础编程

内存泄漏是什么&#xff1f; 内存泄漏即 ML &#xff08;Memory Leak&#xff09; 指 程序在申请内存后&#xff0c;当该内存不需再使用 但 却无法被释放 & 归还给 程序的现象 内存泄漏有哪些情况&#xff0c;对应的解决方案&#xff1f; 内存泄漏的原因归根到底就是当需…

用OpenArk查看Windows 11电脑中全部快捷键并解决热键冲突问题

本文介绍在Windows电脑中&#xff0c;基于OpenArk工具&#xff0c;查看电脑操作系统与所有软件的快捷键&#xff0c;并对快捷键冲突加以处理的方法。 最近&#xff0c;发现有道词典的双击Ctrl功能失效了&#xff0c;不能很方便地翻译界面中的英语&#xff1b;所以&#xff0c;就…

Linux系统Docker部署StackEdit Markdown并实现公网访问本地编辑器

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

UE5 UE4 不同关卡使用Sequence动画

参考自&#xff1a;关于Datasmith导入流程 | 虚幻引擎文档 (unrealengine.com) 关卡中的Sequence动画序列&#xff0c;包含特定关卡中的Actor的引用。 将同一个Sequcen动画资源放入其他关卡&#xff0c;Sequence无法在新关卡中找到相同的Actor&#xff0c;导致报错。 Sequen…

unity 场景烘焙中植物叶片(单面网络)出现的白面

Unity版本 2021.3.3 平台 Windows 在场景烘焙中烘焙植物的模型的时候发现植物的叶面一面是合理的&#xff0c;背面是全白的&#xff0c;在材质球上勾选了双面烘焙&#xff0c;情况如下 这个问题可能是由于植物叶片的单面网格导致的。在场景烘焙中&#xff0c;单面网格只会在一…

饲料厂设备机器有哪些

饲料厂设备机器有哪些 &#xff1f; 饲料厂设备机器主要涉及到物料的加工、压制和混合过程。首先&#xff0c;物料会经过饲料粉碎的处理&#xff0c;使其颗粒细小。然后&#xff0c;物料会经过颗粒饲料机的压制&#xff0c;形成颗粒状的饲料。最后&#xff0c;颗粒饲料会通过混…

map和set的简单介绍

由于博主的能力有限&#xff0c;所以为了方便大家对于map和set的学习&#xff0c;我放一个官方的map和set的链接供大家参考&#xff1a; https://cplusplus.com/ 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque&#x…

TypeScript+React Web应用开发实战

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在现代Web开发中&#xff0c;React和TypeScrip…

c#/ .net8 香橙派orange pi +SSD1306 oled显示屏 显示中文+英文 实例

本文使用香橙派orangepi pi 3ltsSSD1306 oled显示屏作为例子&#xff0c;其它型号的也是一样使用的 在nuget包中安装 Sang.IoT.SSD1306; 以下两个二选一 SkiaSharp;//在window下运行装这个 SkiaSharp.NativeAssets.Linux.NoDependencies;//在linux下运行一定要装这个 在c# .ne…

unity shaderGraph实例-物体线框显示

文章目录 本项目基于URP实现一&#xff0c;读取UV网格&#xff0c;由自定义shader实现效果优缺点效果展示模型准备整体结构各区域内容区域1区域2区域3区域4shader属性颜色属性材质属性后处理 实现二&#xff0c;直接使用纹理&#xff0c;使用默认shader实现优缺点贴图准备材质准…

普通索引和唯一索引详解

前言 面试的时候有时会问面试者&#xff0c;普通索引和唯一索引有什么区别。很多人&#xff0c;甚至工作很多年的工程师回答的千篇一律 “普通索引可以有重复的值&#xff0c;唯一索引不能有重复的值”。于是我又问&#xff0c;这两个索引这两个索引效率哪个高&#xff0c;很少…

腾讯云优惠购买政策大全:新老用户都来瞧瞧!

腾讯云服务器多少钱一年&#xff1f;62元一年起&#xff0c;2核2G3M配置&#xff0c;腾讯云2核4G5M轻量应用服务器218元一年、756元3年&#xff0c;4核16G12M服务器32元1个月、312元一年&#xff0c;8核32G22M服务器115元1个月、345元3个月&#xff0c;腾讯云服务器网txyfwq.co…

script中的defer和async

在HTML中&#xff0c;<script>标签可以使用async和defer两个属性来控制外部JavaScript文件的加载和执行方式。这两个属性的目的是优化页面加载时间&#xff0c;但它们以不同的方式工作。下面是每个属性的具体说明&#xff1a; async属性 当你给<script>标签添加a…

pwa应用打开自动跳转到某个网页网址,并且全屏不显示网址url,就像这个网页也具备了pwa功能

问题描述 如果是只要在同一个域名下配置了pwa功能,那么当从桌面上打开这个pwa软件时,就会像真正的app运行一样,全屏显示,并且不显示网址的,但是如果要动态配置打开pwa时动态加载不同的网址,使用 window.location.href = “网址”这种形式重定向url就会导致pwa出现地址栏…

【MySQL】基本查询(表的增删改查)-- 详解

CRUD&#xff1a;Create&#xff08;创建&#xff09;&#xff0c;Retrieve&#xff08;读取&#xff09;&#xff0c;Update&#xff08;更新&#xff09;&#xff0c;Delete&#xff08;删除&#xff09;。 一、Create insert [into] table_name [(column [, column] ...)] v…

Unity中URP实现水体(水的焦散)

文章目录 前言一、原理1、 通过深度图&#xff0c;得到 对应像素 在 世界空间下的Z值2、得到模型顶点在 观察空间 下的坐标3、由以上两点得到 深度图像素 对应的 xyz 值4、最后&#xff0c;转化到 模型本地空间下&#xff0c;用其对焦散纹理采样 二、实现1、获取深度图2、在顶点…

警惕!2本期刊被剔除!2024年2月Scopus期刊目录已更新!

【SciencePub学术】 ​2024年2月&#xff0c;Scopus数据库迎来本年度第二次更新&#xff01;此次更新后&#xff0c;有94本期刊发生变动&#xff1a; • 剔除&#xff1a;有2本期刊不再被Scopus数据库收录&#xff08;Discontinued titles Jan. 2024&#xff09;&#xff1b; …

【低代码开发_RuoYi_框架】RuoYi框架_前端页面部署/搭建

开源软件的影响力 随着信息技术的快速发展&#xff0c;开源软件已经成为软件开发的趋势&#xff0c;并产生了深远的影响。开源软件的低成本、可协作性和透明度等特点&#xff0c;使得越来越多的企业和个人选择使用开源软件&#xff0c;促进了软件行业的繁荣。然而&#xff0c;…