设计模式之禅读后感

article/2025/8/22 15:29:48

过早优化是万恶之源——Unix编程思想

    让正确的程序更快,要比让快速的程序正确容易得多。

文章目录

      • 前言
      • 六大设计原则
        • *单一职责原则*
        • *里氏替换原则*
        • *依赖倒置原则*
        • *接口隔离原则*
        • *迪米特法则*
        • *开闭原则*
      • 二十三种设计模式
        • 创建型模式
          • *单例模式*
          • *工厂方法模式*
          • *抽象工厂模式*
          • *建造者模式*
          • *原型模式*
        • 结构型模式
          • *代理模式(委托模式)*
          • *装饰模式*
          • *适配器模式*
          • *门面模式*
          • *组合模式*
          • *享元模式*
          • *桥梁模式*
        • 行为型模式
          • *模板方法模式*
          • *中介者模式*
          • *命令模式*
          • *责任链模式*
          • *策略模式*
          • *迭代器模式*
          • *观察者模式(发布订阅模式)*
          • *备忘录模式*
          • *访问者模式*
          • *状态模式*
          • *解释器模式*
      • 设计模式对比
      • 设计模式混编
      • 结束


前言

如果说“四人帮的”《设计模式》是设计模式领域的“圣经”,那么《设计模式之禅》便是得道者对“圣经”的禅悟。它既不像“圣经”那样因为惜字如金、字字珠玑而深奥、晦涩和难懂,又比“圣经”的“注释版”更深刻和全面、更通俗和生动、更接近开发者遇到的实践场景,更具指导性。——互动百科
在这里插入图片描述

读这本书已经有一段时间了,目前对一些常用设计模式也有了一知半解,书中每一个知识点都对应一个具体实例,配合作者的高水平讲解,让读这本书的人更能深层次的理解知识背后的含义。本文主要为个人读书后的理解,理解浅显,以后还要反复阅读,如果有理解错误的地方还望留言指出,不胜感激。

六大设计原则

六大原则是为程序开发而出现的参考规则,遵循这些规则不一定可以让你的程序更快速,但一定能在一定程度上让你的程序更容易扩展。六大原则只是参考原则,程序编写的第一位是程序的正确性,其次再考虑拥抱变化,六大原则遵守有个度的把握,需要开发者根据实际需求具体分析。

单一职责原则

  • 定义:

应该有且仅有一个原因引起类的变更。

  • 好处:
    1. 累的复杂性降低,实现什么职责都有清晰明确的定义;
    2. 可读性提高,复杂性降低,
    3. 可维护性提高。
    4. 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个借口修改只对应相应的实现类有影响,对其他的接口无影响这对类的拓展性、维护性都有很大帮助。

  • 注意:单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或 类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。

里氏替换原则

  • 定义:

所有引用基类的地方必须能透明地使用其子类的对象。
定义已经足够简单,换而言之就是所有可以使用父类的地方,都可以使用子类来代替。

面向对象继承机制的优缺点:

  • 优点:
    ● 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
    ● 提高代码的重用性;
    ● 子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有 父的“种”,“世界上没有两片完全相同的叶子”是指明子与父的不同;
    ● 提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,君不见很多开源框架的扩展接口都是通过继承父类来完成的;
    ● 提高产品或项目的开放性。
  • 缺点:
    ● 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;
    ● 降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;
    ● 增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在 缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构。
  • 里氏替换为继承定义了一个规范:
  1. 子类必须完全实现父类的方法。
  2. 子类可以有自己的个性
  3. 覆盖或实现父类的方法时输入参数可以被放大
    笔记:子类重载父类方法,并且传入参数类型比父类参数类型范围更大,子类就会替代父类传入参数,但执行的方法体还是父类的,子类覆写的方法永远都不会得到执行。
  4. 子类不能缩小父类方法传入参数类型范围,否则引入LSP原则,子类替代父类时会调用子类方法,违背了该原则,会歪曲了父类的意图。所以子类中的方法的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松。
  5. 覆写或实现父类的方法时输出结果可以被缩小。
  • 注意:再类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。
  • 注意:如果子类不能完整的实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建立断开父子继承关系,采用依赖、聚集、组合等关系代替继承。采用里氏替换原则时,尽量避免子类的“个性”。

依赖倒置原则

  • 定义:

高层模块不应该依赖低层模块,两者都应该依赖其抽象
抽象不应该依赖细节。
细节应该依赖抽象。

  • 优点:
    采用依赖倒置原则可以减少类间耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和维护性。

  • 使用依赖倒置原则:
    1. 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备。
    2. 变量的表面类型尽量是接口或者是抽象类。
    3. 任何类都不应该从具体类派生。
    4. 尽量不要覆写基类的方法。
    说明:类间的依赖时抽象,覆写了抽象方法,对依赖的稳定性会产生一定影响。
    5. 结合里氏替换原则使用。
    说明:结合出的通俗原则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。

接口隔离原则

  • 定义:

类间的依赖关系应该建立在最小的接口上。
客户端不应该依赖于它不需要的接口

理解:接口隔离原则,主要是防止类间强耦合性,如果类都能通过接口互相依赖,程序的可扩展将大大提升,同时,接口隔离原则也是适配器模式的必要前置条件。

迪米特法则

  • 定义:

一个对象应该对其他对象有最少的了解。

开发过程中坚持一个原则:如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

  • 核心:迪米特法则的核心就是类间解耦,若耦合,只有弱耦合了以后,类的复用率才可以提高。其结果就是产生了大量的中转或跳转类,导致系统复杂性提高。

使用迪米特法则时要反复权衡,既做到让结构清晰,又做到高内聚低耦合。

开闭原则

  • 定义:

一个软件实体如类、模块和函数应该对拓展开放,对修改关闭。

注意:开闭原则对拓展开放,对修改关闭,并不意味着不做任何修改,低层模块的变化必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

笔记:简而言之就是一个软件实体应该通过拓展来实现变化,而不是通过修改已有代码来实现变化。

总结:这些原则是一个程序员编写代码的基础,这些原则并不是非要完整的实现,里面要有一个度的把握,以单一职责原则来说,如果一味的遵循这个原则,虽然接口与类的设计变得单纯了,但是接口的碎片化却变得非常严重,最后只能呛死在接口的海洋里。原则是为了辅助开发人员来实现更加健壮的程序,同时也需要开发人员根据业务需求做出相应的变更,开发人员的根本是为了写出健壮,扩展性良好的程序,如果只一味遵循原则,而忽略了程序本身的需求与流程,那就本末倒置了。


二十三种设计模式

二十三种设计模式,经过了各种环境的测试与改良而来,是开发人员智慧的结晶,可以说已经是各种环境下程序编码最好的设计体现了。熟练使用这些设计模式,一定可以让程序更加健壮。

  • Java中设计模式基本分为三大类:
    创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
    结构型模式(7种):适配器模式,装饰模式,代理模式,门面模式,桥接模式,
    组合模式,享元模式。
    行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

创建型模式

单例模式

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

在这里插入图片描述

抽象工厂模式

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类。

在这里插入图片描述

建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

在这里插入图片描述

原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

在这里插入图片描述

结构型模式

代理模式(委托模式)

为其他对象提供一种代理以控制这个对象的访问。

在这里插入图片描述

装饰模式

动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

在这里插入图片描述

适配器模式

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

在这里插入图片描述

门面模式

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

在这里插入图片描述

组合模式

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

在这里插入图片描述

享元模式

使用共享对象可有效地支持大量的细粒度对象。

在这里插入图片描述

桥梁模式

将抽象和实现解耦,使得两者可以独立的变化。

在这里插入图片描述

行为型模式

模板方法模式

定义一个操作中的算法的框架,而将一些步骤延迟到了子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

在这里插入图片描述

中介者模式

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立的改变他们之间的交互。

在这里插入图片描述

命令模式

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

在这里插入图片描述

责任链模式

使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

在这里插入图片描述

策略模式

定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。

在这里插入图片描述

迭代器模式

它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。

在这里插入图片描述

观察者模式(发布订阅模式)

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。(鼎鼎大名的Rxjava就是基于观察者模式实现的)

在这里插入图片描述

备忘录模式

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

在这里插入图片描述

访问者模式

封装一些所用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

在这里插入图片描述

状态模式

当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

在这里插入图片描述

解释器模式

给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

在这里插入图片描述

总的来说,23种设计模式是前辈们无数实践与创新得来的经过时间与需求变化的重重考验才被流传下来,熟练使用这些设计模式将会为程序的健壮性和可拓展性提高一个层次。但别孤立的思考一个模式,僵化的套用一个模式会让开发者受害无穷
23种设计模式并不是恒定不变的,其中迭代器模式已经被各种语言封装起来,现在我们基本上不用自己实现迭代器,该模式也逐渐没落了。23种设计模式随时可变,只要有想法,甚至可以自己去探究新的模式。

设计模式对比

  • 工厂模式建造者模式进行对比:
    工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程,虽然最终执行结果一样,但是侧重点是不同的。在开发过程中如何选用工厂方法还是建造者模式,完全取决于设计时的意图,如果需要详细关注一个产品部件的生产、安装步骤,则选择建造者,否则选择工厂方法模式

23种设计模式中有些可能有较多的相似性,但每个模式都有其特性,开发者需要根据业务需求选择,还可以对多个设计模式进行混合使用。设计模式只是提供了一个解决问题的意图,而没有具体定出一个设计模式必须这样实现,必须是这样的代码,灵活运用模式才是其根本。

设计模式混编

设计模式不是完美的,每个设计模式都或多或少的有一些缺陷,但是可以使用设计模式混编来避免这种缺陷。书中介绍了几种典型设计模式的混编,分别是:命令模式+责任链模式+模板方法模式,实现UNIX命令移植到Windows系统;工厂方法模式+策略模式+门面模式,实现一个小型交易系统;观察者模式+中介者模式,讲解按钮OnClick的触发原理。

作者使用设计模式组合,开发出了高内聚、低耦合、对修改关闭,对拓展开放等优点集一身的非常健壮的程序,说明了23种设计模式并不是固定写死、不能共存的,开发人员应该深入了解这些设计模式,对业务需求也要有深刻理解,这样才能拥抱变化,从容处理。

设计模式不是工具,他是软件开发的哲学,他能知道你如何去设计一个优秀的
架构、编写一段健壮的代码、解决一个负责的需求。因为它是指导思想,你可以在此基础上自由发挥,甚至是自己设计出一套设计
模式。

结束

    我在读此书时时常有“原来还可以这样”的感叹,读完此书感觉自己收获良多,在日常的代码编写时,也时常回顾书上所讲,主动向一些常用的设计模式靠拢;阅读一些开源项目时,也与书上知识点一一印证,希望通过实战与理论的结合,让自己一直进步。
    编程是一门艺术,设计模式更是编程的指导思想。书上说,心中无设计模式,而所想所写处处是设计模式,这才是最高境界。希望有一天可以站在一个更高的层次去赏析程序代码,完成代码工人到架构师的蜕变。

书中有言:代码是让人读的,然后才是让机器执行。

牢记教诲,正确理智的选择设计模式。
听说巧克力和音乐更配,但对于开发人员来说,健壮的程序和整洁的代码才更配。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/gD7E4IBt.shtml

相关文章

设计模式之禅笔记

设计模式PK 创建类模式PK 工厂方法模式 VS 建造者模式 工厂方法模式注重的是整体对象的创建方法。建造者模式注重的是部件构建的过程。 工厂方法模式的对象粒度较粗,建造者模式的产品对象粒度较细。 抽象工厂模式 VS 建造者模式 抽象工厂模式也是注重产品的整…

《设计模式之禅》(第2版)

第一部分 大旗不挥 谁敢冲锋 —— 6大设计原则全新解读 第1章 单一职责原则 单一职责原则,Single Responsibility Principle,简称SRP,有且只有一个原因引起类/接口的变更;即一个接口/类只有一个职责,只负责一件事…

设计模式之禅《一》 大旗不挥,谁敢冲锋 ——6大设计原则

设计模式之禅《一》大旗不挥,谁敢冲锋 ——6大设计原则 《一》 六大原则 一:单一职责原则 1、单一职责原则最难划分的就是职责 2、有两个可以变化的原因放到了一个接口中,这就为以后的变化带来了风险。 3、对于单一职责原则,…

设计模式之禅(六大设计原则)

1.单一职责原则(Single Responsibility Principle) 也就是职责划分要明确,单一职责原则提出了一个编写程序的标准,用“职责”或者“变化原因”来衡量接口或者类设计的是否优良,但是“职责”或者“变化原因”都是不可度量的,因项目…

什么是ASCII码

ASCII码英文全称America Standard Code for Information Interchange,中文意思:美国信息交换标准码。它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。适用于所有拉丁文字字母,ASCII码有7位码和8位…

最全ASCii 码表和说明

A的ASCII码是65,a的ASCII码是97。 ASCII码表中,小写字母排在大写字母的后面,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应的小写字母的ASCII码数值就算出来了,是大写字母的ASCII码数…

ASCII码

字符编码即ASCII码(American Standard Code for Information Interchange,美国信息交换标准码,国际通用的计算机内的字符数字的二进制编码),它是7位二进制编码,总共有128个符号,包括英文26个大写字母&#…

什么叫ASCII码

一个字符A,以 字符和整型都可以输出。因为字符A也是以二进制存储,这个二进制对应一个整数 那究竟什么是ASCII码? ASCII不是一个值,而是一种规定。 ASCII规定了不同字符是使用哪个整数值表示 它规定: A --65 B --…

关于ASCII码的转换

目录 ASCII码表ASCII码与字符之间的转换 ASCII码表 ASCII码与字符之间的转换 python中chr()和ord()两个函数可以实现ASCII码与字符之间的转换, 两者之间的关系 转换举例 stringbsuahisas num_list[ord(i) for i in string] str_list[chr(i) for i in num_list] p…

ASCII码介绍

ASCII码 概念 ASCII(American Standard Code for Information Interchange)的缩写(美国标准信息交换代码),已被国际标准化组织ISO采纳,作为国际通用的信息交换标准代码。 诞生背景 计算机对数据的识别、运算和存储都建立在二进制…

ASCII编码

ASCII编码 ASCII编码的概念对控制字符的解释详细说明 ASCII编码的概念 计算机是以二进制的形式来存储数据的,它只认识 0 和 1 两个数字,我们在屏幕上看到的文字,在存储之前都被转换成了二进制(0和1序列),在…

ascii码a和A为什么差32而不是26

ascii码a和A为什么差32而不是26? A的ASCII码是65,a的ASCII码是97; ASCII码表中,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应的小写字母的ASCII码数值就算出来了,是大写字…

ASCII码详解

ASCII简介 ASCII 码使用指定的 7 位或 8 位二进制数组合来表示 128 或 256 种可能的字符。标准 ASCII 码也叫基础ASCII码,使用 7 位二进制数来表示所有的大写和小写字母,数字 0 到 9、标点符号, 以及在美式英语中使用的特殊控制字符。其中&a…

a到z的ascii码值是多少_a和A对应的ASCII码数值分别是多少啊?

展开全部 A的ASCII码是65,a的ASCII码是97。 ASCII码表中,小写字母32313133353236313431303231363533e78988e69d8331333366303066排在大写字母的后面,一个字母的大小写数值相差32,一般知道大写字母的ASCII码数值,其对应…

输出ASCII码

输出字符的ASCII码 从键盘输入一个字符&#xff0c;按规定格式输出这个字符及它的ASCII码。例如&#xff1a; 输入 A 输出 “The ASCII of A is 65”.//输出的数值在双引号以内// 代码&#xff1a; ​ #include <stdio.h>int main() {char a;scanf("…

ascii码中的A的代码是什么?

ASCII&#xff08;American Standard Code for Information Interchange&#xff0c;美国标准信息交换代码&#xff09;是基于拉丁字母的一套电脑编码系统&#xff0c;主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统&#xff0c;并等同于国际标准ISO/IEC…

system函数阻塞问题

system()函数是阻塞方式进行的&#xff0c;他会新建一个进程! system代码执行完毕才继续执行&#xff01; 注意一点&#xff0c;如下的命令&#xff1a; #include <bits/stdc.h> #include <windows.h> using namespace std; int main() {std::cout << "…

Linux system函数的执行命令并获取状态

在linux中&#xff0c;可以通过调用system函数执行linux命令&#xff0c;但是如何获取执行命令的结果状态呢&#xff0c;也就是是否执行成功。 #include <stdio.h> #include <stdlib.h>int main() {int ret -1;ret system("cat /proc/mounts | grep sda"…

system函数常见用法

system函数 1.用来执行windows常用命令 我们知道 C语言是没有自己的窗口的&#xff0c;比如我们用printf函数在黑框上输出Hello World是其实是调用了windows的DOS交互窗口。 我们在C语言程序中用system可以给操作系统发送指定&#xff0c;其作用与直接在DOS窗口发送指令进行交…

system函数的总结

system函数的总结 2014-10-30 20:22 1216人阅读 评论(2) 收藏 举报 分类&#xff1a; 系统编程&#xff08;17&#xff09; 最近在看APUE第10章中关于system函数的POSIX.1的实现。关于POSIX.1要求system函数忽略SIGINT和SIGQUIT&#xff0c;并且阻塞信号SIGCHLD的论述&…