当前位置: 首页 > news >正文

C++设计模式

面向对象编程的一些术语:

延迟到子类: 定义一个虚函数,让子类来重写获实现他。这其实就是支持子类去 变化。
扩展: 继承 + 多态,即,子类继承基类 并对其虚函数进行 override
依赖: 一般指编译时依赖,如:A依赖B,那么在编译的时候,编译器需要先编译 B,才能再编译 A。本篇指的一般是编译时依赖,如果是运行时依赖会特别说明。


1、面上对象设计的8大原则

  • 依赖倒置:
    隔离变化。高层模块(需要稳定)不应该依赖于低层模块(是易变化的),二者都应该依赖于抽象(稳定的)。
    抽象(稳定)不应该依赖于实现细节(易变化的),实现细节应该依赖于抽象(稳定)。
  • 开放封闭:
    类模块应该是可扩展(增加)的,但是不可修改的。
  • 单一职责:
    一个类应该仅有一个引起它变化的原因。变化的方向隐含着类的的责任。(类不能太臃肿,过多的责任会把类往不同方向撕扯)
  • 替换原则:
    子类能够替换基类,所有使用父类的地方把子类传过去也能用。
  • 接口隔离:
    接口应该尽量小。即,有必要的时候才将方法放入 public
  • 优先使用对象组合,而不是类继承。
  • 封装变化点:
    使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响
  • 针对接口编程,而不是针对实现编程 。(客户只需知道接口即可,无需获取变量类型)

管理变化,提高复用

2、设计模式

2.1设计模式 要做的事情及其意义

在软件的 变化 稳定 中间寻找隔离点,从而分离他们,从而更好地管理变化。

2.2 如何很好的应用设计模式

在应用设计模式时,关键就是要区分出软件体系结构中 哪些是稳定的,哪些是变化的。
动态地看 一个软件的结构层次。

2.3 真正学习设计模式时

拿到一张设计模式的类图,重点要区分出类图中哪些是稳定的,哪些是变化的。

3、模板方法模式

早绑定:一个晚的东西调用一个早(库)的东西。
晚绑定:反过来。(由库来调用我们写的东西。)这是该模式在代码中的体现形式。

4、策略模式

表现形式: 多态。定义一个基类,我们可以扩展其子类并重写其虚函数,从而实现变化。而调用这些方法的接口不用变。

代码中如果出现了if elseswitch case的这种结构,通常是使用策略模式的特征,此时你就要考虑一下未来会不会增加其他的else if分支,如果有可能那么此时应该使用策略模式。但如果if else里判断的是星期几,情况固定,那么就不必使用策略模式。

“当你看到if else时,你就闻到了代码中的坏味道”——马丁·弗勒

5、观察者模式

这里是引用
摘自:https://www.midlane.top/wiki/pages/viewpage.action?pageId=26181878

6、装饰模式

表现形式: 组合 + 多态。

这里是引用
摘自:https://www.midlane.top/wiki/pages/viewpage.action?pageId=26181888

在这里插入图片描述
装饰模式应用的要点在于解决“主体类在多个方向上的扩展功能”

装饰模式达到的效果:各个类在编译时是各司其职,但可以通过编写代码实现在运行时随意装配组合功能(但编译时,没有实现这种功能的类)。

7、桥模式

在这里插入图片描述

桥模式和装饰模式很相似,它们的区别是继承体系的数量不同。装饰模式只有一个继承体系;而桥模式有两个继承体系,他们之间由一个指针联系起来,这个指针就像桥一样。

当一个类中有多个非常强的变化维度时,就把属于某个变化维度的成员打包在一起单独作为一个基类,并且引一个指针指向它。

8、工厂方法模式

解决的问题: 由于需求的变化,需要创建的对象的具体类型经常变化。我们需要避免直接new一个对象,从而避免这种紧耦合。

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。

9、抽象工厂模式

和工厂方法模式很像都是用来避免在创建对象时的紧耦合。但抽象工厂解决的是创建【一系列相互依赖的对象】的创建工作。

可以将工厂方法 看作 抽象工厂的一个特例,即,要创建的对象只有一个,而不是一个系列。

10、原型模式

使用场景和工厂模式很相似,都是用来避免在创建对象时的紧耦合。

什么时候使用该原型:当使用工厂方法创建对象所需要的步骤很复杂,且 需要考虑 并 保留对象的中间状态时,就需要使用原型模式。

11、构建器模式

该模式和模板方法模式很像,但构建器模式的思考方式更加细化,他是从构建对象的角度来看的。

构建器模式将复杂对象的构建与其表示相分离,使得同样的构建流程(稳定)可以创建不同的表示(变化)。

12、单例模式

单例模式解决的不是抽象问题,而是性能问题。
单例模式保证某个类只有一个实例,并提供一个该实例的全局访问点。

单例模式的实现一般有两种方式:
懒汉模式: 第一次用到类的实例时才实例化。
饿汉模式: 单例类定义的时候就进行实例化。
更多懒汉模式和饿汉模式可以参考这里。

普通的单例模式实现方法是非线程安全的,因此多线程编程中使用单例模式涉及到锁,这里牵扯到很多问题。所以先记几篇博客:
Boost线程库学习笔记
boost::scope_lock简要总结
单例模式和线程安全
单例模式和线程安全

13、享元模式

单例模式解决的也不是抽象问题,而是性能问题。即,当需要创建很多对象时,我们让他们共享一个对象,而不是真的去创建这么多对象。
运用共享技术有效地支持大量细粒度的对象。

使用享元模式创建的对象一般都是只读的,否则共享就不成立了。

14、门面模式

在这里插入图片描述

将系统内的变化圈起来,对系统外提供统一的接口访问系统内。
对外松耦合,对内高内聚。

15、代理模式

为其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问。
增加间接层,在间接层中实现一些不为外界所知的功能。在具体实现中,间接层中需要做的工作可能非常庞大。

16、适配器模式

在这里插入图片描述
在这里插入图片描述

将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。

17、中介者模式

在这里插入图片描述
在这里插入图片描述
(李建忠C++设计模式第17集17分10秒处讲解了四种接口隔离模式的区别)

18、状态模式

在这里插入图片描述

19、备忘录模式

在这里插入图片描述
备忘录模式的思想是:在不破坏封装性的前提下,捕获一个对象的内部状态(即,不能让外部知道对象的实现细节),并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态。

如今该模式的实现方式已经基本脱离了面向对象编程,而是采用序列化等方式。所以,对于该模式我们只需知道其思想即可,而实现方式另外去学习。

21、组合模式

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

组合模式采用树形结构来实现普通存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。

22、迭代器模式

在C++中该设计模式已经被STL标准库中的迭代器iterator所取代(用模板+适配器模式实现),而在其他语言中遍历不同类型的容器确实是用迭代器模式实现的。

23、职责链模式

在这里插入图片描述

可以做到在运行时辨析哪个处理者可以处理这个请求。
不过该模式在今天也基本用的很少了。

24、命令模式

把行为抽象为对象(类似于函数对象)。
目前,在C++中,函数对象已经基本取代了命令模式,但命令模式在Java等其它语言得到了广泛的应用。

25、访问器模式

表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。
在这里插入图片描述
弄清楚上图中哪些部分可变,哪些部分不可变很重要。

访问器模式虽然能够动态地为整个对象体系中的所有类添加新方法,但是,使用该模式的前提条件也是很苛刻的。所以,在实际开发中很少有能用该模式的情景。
在这里插入图片描述

26、解析器模式

在这里插入图片描述
应用场景:解析类似于 “肆仟叁佰伍拾陆”,这样的文法,将其转换成数字表示,就可以使用解析器模式。

解析器模式比较是和简单的文法表示,对于复杂的文法表示,解析器模式会产生很大的类层次结构。目前,解析器模式用的也比较少。

27、设计模式总结

27.1 C++对象模型

指针指向多态对象是松耦合对象模型基础。
在这里插入图片描述

27.2 关注变化点和稳定点

一般项目中变化点和稳定点的数量呈正态分布。
在这里插入图片描述

27.3 什么时候不用模式

在这里插入图片描述

27.4 经验之谈

在这里插入图片描述

27.5 设计模式成长之路

在这里插入图片描述

相关文章:

  • C++ 嵌套类
  • CMake指令解析 set(CMAKE_CXX_FLAGS “$ENV{CXXFLAGS} -rdynamic -O3 -fPIC -ggdb -std=c++11 -Wall -Wno-deprec
  • 记一个测试sylar服务器日志模块时遇到的一个非常奇怪的问题
  • syscall()
  • 记一个编写宏时的错误
  • C++中全局变量,静态变量,静态局部变量 的初始化和内存分配问题
  • C++ 模板实现单例模式
  • 《C++ Primer》 异常
  • C++父类和子类指针的相互赋值和转换
  • 算法设计与分析————期末死亡冲刺
  • 现代软件工程————期末死亡冲刺
  • std::string::npos 常量解析
  • 练习4-3 求给定精度的简单交错序列部分和 (15 分)本题要求编写程序,计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... 直到最后一项的绝对值不大于给定精度eps。
  • 浙大版《C语言程序设计(第4版)》题目集 练习4-6 猜数字游戏 (15 分)
  • 练习4-7 求e的近似值 (15 分)自然常数 e 可以用级数 1+1/1!+1/2!+⋯+1/n!+⋯ 来近似计算。本题要求对给定的非负整数 n,求该级数的前 n+1 项和。
  • [译]前端离线指南(上)
  • 【347天】每日项目总结系列085(2018.01.18)
  • android图片蒙层
  • AngularJS指令开发(1)——参数详解
  • CSS中外联样式表代表的含义
  • Git 使用集
  • Java比较器对数组,集合排序
  • php中curl和soap方式请求服务超时问题
  • use Google search engine
  • 编写符合Python风格的对象
  • 程序员最讨厌的9句话,你可有补充?
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 将 Measurements 和 Units 应用到物理学
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 悄悄地说一个bug
  • 使用API自动生成工具优化前端工作流
  • 使用SAX解析XML
  • 算法-图和图算法
  • 项目管理碎碎念系列之一:干系人管理
  • hi-nginx-1.3.4编译安装
  • raise 与 raise ... from 的区别
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​Python 3 新特性:类型注解
  • "无招胜有招"nbsp;史上最全的互…
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #Ubuntu(修改root信息)
  • (4)logging(日志模块)
  • (js)循环条件满足时终止循环
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (四)JPA - JQPL 实现增删改查
  • (状压dp)uva 10817 Headmaster's Headache
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting