【设计模式】六大设计原则

设计原则

    • 研究 23 种设计模式是困难的,甚至是没必要的
    • 六大设计原则
      • 零、单一职责原则
      • 开闭原则
      • 里氏代换原则
      • 依赖倒置原则
      • 接口隔离原则
      • 迪米特法则
      • 合成复用原则

研究 23 种设计模式是困难的,甚至是没必要的

设计模式有23种,我认为对普通人来说想要灵活掌握这23种设计模式是十分困难的。

  1. 设计模式的书中,介绍每一种设计模式,往往都举一个形象有趣的例子,然后读者会被有趣的例子和实现所吸引,而其背后蕴含的道理往往很难通过简单的思考来想清楚。
  2. 意识到上一点的人,通过简单思考后,觉得23种设计模式就像23种模板。23 这个数字已经足够大,大到背会这23个模板都是一个比较大的工程量。于是,学习者会转向记忆这23中模板上,并且最后以记不住这些模板告终。

首先,记忆模板很重要。学习的本质就是:记忆 + 思维。但是记忆哪些东西才是最关键的。记住那些关键假设,推理出进一步的结论。如果再次迭代,记住下一步结论,就能推理出下一步的结论。学习就是这样循环往复。
因此,只记忆模板,不求甚解是学习的大忌。

设计模式难学的第二个难点是思维容易发散,没有统一的思维切入点。光靠 23 种模板,很难让人明白,这种设计比那种设计好在哪里?应该怎样向好的方向去设计软件?23 种设计模式,反而使大脑更发散了。

设计模式底层的底层原理其实是六大设计原则。我认为仔细揣摩这六大原则,使用六大原则来分析23种设计模式的利弊,才是学习设计模式的正途。

软件设计是一个哲学问题。更注重设计的利弊思辨,而不是一个固定的答案。而大多数人包括我缺乏这样的思辨能力。六大设计模式,可以辅助我们分析设计的好坏。

六大设计原则,是针对面向对象的设计模式的原则,也就是针对 封装、继承和多态 的使用原则。

  • 零、单一职责原则:这是所有模块设计的原则,确保功能模块化,与面向对象无关。
  • 一、开闭原则:对拓展(继承)开放,对修改关闭
  • 二、里氏替换原则:子类不改变父类原有职责
  • 三、依赖倒置原则 :依赖抽象接口,不依赖具体实现
  • 四、接口隔离原则:拆分大接口
  • 五、迪米特法则 :对别的模块知道的越少越好,最好仅知道少量的接口。
  • 六、合成复用原则:多用组合,少用继承

这六大原则也不是必须遵守的。因为这些原则都是定性的描述,多用xx,少用 xx等等。我们遵循这些模式,需要遵循到什么程度是很难判断的?毕竟现实中都是实在的量,接口有几个参数,我继承了几个类,等等。衡

因此我们要做得是分析利弊:

  1. 如果违背了某一原则,我们要付出什么样的代价
  2. 如果遵循了某一原则,我们得到了什么要的好处

软件设计本身就是一场不同设计目标之间的权衡。抽象程度高,则代码更灵活,但是可读性会变差。高性能,则需要更多缓存。所以我要说的是,如果违背原则的代价可以承受,那就可以违背原则。

事实上,由于软件设计是一个哲学问题,有另外一本书叫 《软件设计的哲学》写的也很不错,其中系统阐述了什么是软件的复杂性。里面的一些观点,貌似还要和这里相反。所以说,哲学是讲辩证法的。

六大设计原则

零、单一职责原则

一个类只能有一个引起它变化的原因。这个原因就是这个类的职责。

但说到底,职责的划分也是设计,把两件事当做一个职责也不是不可能。

如果违背了这一原则,一个类存在两个以上的职责,有以下两点代价

  1. 一个职责的变化可能会削弱或者抑制这个类实现其他职责的能力;
  2. 当用户仅需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。

所以,如果几个职责的实现不会有太大变化,或者这些职责只在一个地方用的时候,违背这个原则也无碍

开闭原则

对扩展开放,对修改关闭

拓展就是继承。通过继承抽象接口来实现新的功能,而不是修改核心功能代码。

里氏代换原则

任何基类出现的地方,子类一定可以出现。子类可以拓展,但不能改变父类原有的功能。

  • 子类不能覆盖父类的非抽象方法
  • 子类中可以增加自己特有的方法。
  • 确保兼容父类的用法:
    • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
    • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

依赖倒置原则

依赖抽象,不要依赖实体。加入 A 模块依赖 B 模块,可以选择不要直接依赖 B 模块,而让 A 依赖一个接口IB,然后使用 B 实现一个 IB。从图上看,对 B 的依赖发生了反转
在这里插入图片描述

接口隔离原则

将庞大的接口拆分成小接口,放在不同的模块中去实现。

迪米特法则

最少知道原则。每个模块对于其他单元只能拥有有限的知识。尤其是要依赖接口,而不是依赖具体实现。

合成复用原则

多用合成聚合,少用继承。继承是一个很强的依赖。体现在

  • 对基类的修改会影响所有子类
  • 子类必须实现基类所有的抽象接口
  • 子类被强制拥有了基类的所有内容。因此:
    • 实现子类还需要理解所有基类的其他已实现的接口。否则,你的继承就不成立,因为你不全面了解你的父亲,你就解释不了为什么要继承。

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

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

相关文章

【C++成长记】C++入门 | 类和对象(上) |类的作用域、类的实例化、类的对象大小的计算、类成员函数的this指针

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:C❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、类的作用域 二、类的实例化 三、类对象模型 四、this指针 1、this指针的引出 2 this指针的特…

机械转行网络安全自学经历,零基础学网络安全,血泪总结的干货

机械转行网络安全自学经历,零基础学网络安全,血泪总结的干货 我为什么转行.转行之路面试之路自学路上的学习资源 求职路上亦是如此,打开这篇文章,相信你也有转行的想法。和身边的朋友聊过,入职后的他们,或…

linux 内存寻址

(持续更新) 相关概念 查看的书籍为 深入linux内核 内存地址 当使用80x86(32位)微处理器时,一般分为三种不同的地址: 逻辑地址 包含在机器语言指令中用来指定一个操作数或一条指令的地址。每一个逻辑地址…

踩了一堆坑,终于掌握了postgreSQL主从流的精髓

📢📢📢📣📣📣 哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】!😜&am…

【Linux】序列化与反序列化{服客编程/守护进程/JSON}

文章目录 1.引入2. 静态成员函数3.TCP:传输控制协议4.守护进程4.0前台进程4.1介绍4.2认识4.3会话4.3ps axj4.4理解4.5/dev/null4.6守护进程和孤儿进程 5.JSON6.完整代码6.1Makefile6.2Socket.hpp6.3Protocol.hpp6.4Log.hpp6.5Daemon.hpp6.6TcpServer.hpp6.7Client.c…

第二期书生浦语大模型训练营第三次作业

任务一:在茴香豆 Web 版中创建自己领域的知识问答助手 构建个人回答助手 进入web页面,传输属于自己的文件,此处进行输入大量投资领域资料,构建个人投资者问答助手 回答示例 茴香豆缺陷 此处会发现茴香豆仍然存在一些缺点&#…

Element-UI 自定义-下拉框选择年份

1.实现效果 场景表达&#xff1a; 默认展示当年的年份&#xff0c;默认展示前7年的年份 2.实现思路 创建一个新的Vue组件。 使用<select>元素和v-for指令来渲染年份下拉列表。 使用v-model来绑定选中的年份值。 3.实现代码展示 <template><div><el-…

数字乡村创新实践探索农业现代化与农村治理现代化新路径:科技赋能农村全面振兴与农民幸福生活

目录 引言 一、数字乡村与农业现代化 1、智慧农业技术的应用 2、农业产业链的数字化转型 二、数字乡村与农村治理现代化 1、农村信息化水平的提升 2、农村治理模式的创新 三、科技赋能农村全面振兴与农民幸福生活 1、提升农业生产效益与农民收入 2、促进农村产业结构…

DAY9|28. 实现 strStr()、459.重复的子字符串

28.实现 strStr&#xff08;&#xff09;、459重复的子字符串 28. 实现 strStr()减一版next数组时间复杂度分析前缀表统一减一 C代码实现前缀表&#xff08;不减一&#xff09;C实现 459.重复的子字符串移动匹配KMP前缀表统一减一前缀表&#xff08;不减一&#xff09;的C代码实…

深度学习图像处理基础工具——opencv 实战2 文档扫描OCR

输入一个文档&#xff0c;怎么进行文档扫描&#xff0c;输出扫描后的图片呢&#xff1f; 今天学习了 opencv实战项目 文档扫描OCR 问题重构&#xff1a;输入图像 是一个含有文档的图像——> 目标是将其转化为 规则的扫描图片 那么怎么实现呢&#xff1f; 问题分解&#…

LeetCode 94 二叉树的中序遍历

题目描述 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入…

Linux登录访问限制

Linux系统下&#xff0c;用户密码的有效期可以通过编辑/etc/login.defs文件控制&#xff1b;密码复杂度规则设定需要通过/etc/pam.d/system-auth文件控制&#xff1b;登录失败次数限制通常由/etc/pam.d/login文件限制&#xff0c;可使用pam_tally2模块进行设置。 Linux系统下的…