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

【HeadFirst 设计模式】设计模式总结与C++案例

文章目录

  • 引言
  • 一、软件设计固有的复杂性
  • 二、设计原则
  • 三、前置要求
  • 四、设计模式代码案例

“每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动”。——Christopher Alexander

  上面这段话可以说是设计模式为什么会被总结归纳并值得学习的原因——“复用前人的经验”。
  你在软件开发过程中遇到的大部分问题,其实你的先辈都曾遇到过,并且已经做了归纳,你只需学习这些经验并实践之就能解决你眼前的困难。
  当然,你也可能选择无视它,自己尝试去解决,但最终的效果大概率差强人意,并且在此过程中也浪费了大量时间。而当你撞了无数次南墙再回过头来看它时,可能这时你才会真正领略到它的魅力。

引言

  本文主要针对《Head First设计模式》中的经典案例给出相应的C++版本,并对一些模式进行简单归纳,在此过程中并不会针对具体模式做深入分析,因为这些东西已经有人做过了,写本文的初衷也只是我自己想写个笔记简单归纳一下。

  模式是在某情景下,针对具体问题给出的某种解决方案。

  因此,这里会顺带给出一些案例,你可以先按照自己的想法,代入其中,尝试给出自己的解,之后再来看案例。通过对比,可能会留下更深刻的印象。

一、软件设计固有的复杂性

建筑商从来不会去想给一栋已经建好的100层高的楼房底下再新修一个小地下室——这样做花费巨大且注定要失败。然而令人惊奇的是,软件系统的用户在要求做出类似改变时却不会仔细考虑,而且他们认为只是需要简单编程的事。

  回想一下你每天都是为了什么而加班你就会发现:其实软件设计复杂的根本原因无外乎两个字:变化

  • 客户需求的变化
  • 技术平台的变化
  • 开发团队的变化
  • 市场环境的变化

  •  各种各样的变化每天都在冲击着你的程序!

如何解决复杂性?

  • 分解

  人们面对复杂度很高的事情有一个常见的做法:即分而治之,将大问题分解为小问题,将复杂问题分解为多个简单问题。

  • 抽象

  更高层次来讲,人们处理复杂性有一个通用的技术,即抽象。由于不能掌握全部的复杂对象,我们选择忽视它的非本质细节,而去处理泛化和理想化了的对象模型。

软件设计的金科玉律:复用!

二、设计原则

(1)依赖倒置原则(DIP)

  • 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
  • 抽象(稳定)不应该依赖于变化),实现细节应该依赖于抽象(稳定)。

(2)开放封闭原则(OCP)

  • 对扩展开放,对更改封闭。
  • 类模块应该是可扩展的,但是不可修改。

(3)单一职责原则(SRP)

  • 一个类应该仅有一个引起它变化的原因。
  • 变化的方向隐含着类的责任。

(4)Liskov 替换原则(LSP)

  • 子类必须能够替换它们的基类(IS-A)。
  • 继承表达类型抽象。

(5)接口隔离原则(ISP)

  • 不应该强迫客户程序依赖它们不用的方法。
  • 接口应该小而完备。

(6)优先使用对象组合,而不是类继承

  • 类继承通常为“白箱复用”,对象组合通常为“黑箱复用”
  • 继承在某种程度上破坏了封装性,子类父类耦合度高。
  • 而对象组合则只要求被组合的对象具有良好定义的接口,度低。

(7)封装变化点

  • 使用封装来创建对象之间的分界层,让设计者可以在分界的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。

(8)针对接口编程,而不是针对实现编程

  • 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
  • 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
  • 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案

三、前置要求

  • 掌握C++的基本语法;
  • 对“封装”,“继承”,“多态”有所了解(尤其是多态);
  • 了解C++派生类与基类之间有三个特殊关系:
    • 派生类对象可以使用基类的方法,条件是方法不是私有的。
    • 基类指针可以在不进行显式类型转换的情况下指向派生类对象。
    • 基类引用可以在不进行显式类型转换的情况下引用派生类对象。

  在开始之前,这里给出一段代码,你可以先推测一下运行结果,再自己跑一下,如果全都判断对了,说明你已基本具备上述要求。

#include <iostream>
using namespace std;class parent
{
public:virtual void show(){cout << "parent -> show" << endl;}
};class son : public parent
{
public:void show(){cout << "son -> show" << endl;}
};void passByReference(parent& p)
{p.show();
}void passByPointer(parent* p)
{p->show();
}void passByValue(parent p)
{p.show();
}int main()
{son s;passByReference(s);passByPointer(&s);passByValue(s);return 0;
}

PS: 复制这段代码,在线运行

四、设计模式代码案例

4.1 策略模式

策略模式 定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

4.2 观察者模式

观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

4.3 装饰者模式

装饰者模式 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

4.4 工厂模式

工厂方法 模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

抽象工厂模式 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

4.5 单例模式

单例模式 确保一个类只有一个实例,并提供一个全局访问点。

4.6 命令模式

命令模式 将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其它对象。命令模式也支持可撤销的操作。

4.7 适配器模式与外观模式

适配器模式 将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

外观模式 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

持续更新中…


http://www.mrgr.cn/news/60613.html

相关文章:

  • 深入计算机语言之C++:类与对象(下)
  • 前端零基础入门到上班:【Day1】什么是前端?
  • 51单片机完全学习——LCD1602液晶显示屏
  • Unsupervised Domain Adaptation by Backpropagation
  • 正则表达式使用举例一(Python下)
  • jieba:智能文本处理的利器,结巴中文分词
  • 外包干了30天,技术明显退步
  • 内网穿透之网络层ICMP隧道
  • 基于SSM的宠物猫狗商业系统设计与实现
  • Chrome异步编程
  • 关于群辉920+更新升级系统后SSD固态存储不受当前DSM版本支持的解决方法
  • python实战(四)——RAG预热实践
  • ssm智慧社区电子商务系统+vue
  • Radar Fields: Frequency-Space Neural Scene Representations for FMCW Radar 笔记
  • 容器化实践:优化DevOps环境下的容器交付流程
  • 【CSS/SCSS】@supports的介绍与用法
  • 【深度学习|地学应用】人工智能技术的发展历程与现状:探讨深度学习在遥感地学中的应用前景
  • arduino uno R3更换328pb-au芯片,烧录bootloader
  • “药品追溯到客户管理:数字化转型下的药企发展之路”
  • 基于LLaMA Factory对LLama 3指令微调的操作学习笔记
  • 新增、修改弹窗封装
  • java溯本求源之基础(二十七)之--Map常用子类及源码分析(6000字长文)
  • 中项到高项:软考信息系统项目管理师证书进阶指南
  • Pytest用例执行顺序和跳过执行详解
  • SQL-lab靶场less1-4
  • 《C++ 旧项目全局变量模块化改造:稳扎稳打,守护原有功能》