重温设计模式--2、设计模式七大原则
文章目录
- 1、开闭原则(Open - Closed Principle,OCP)
- 定义:
- 示例:
- 好处:
- 2、里氏替换原则(Liskov Substitution Principle,LSP)
- 定义:
- 示例:
- 好处:
- 3、依赖倒置原则(Dependency Inversion Principle,DIP)
- 定义:
- 示例:
- 好处:
- 4、单一职责原则(Single Responsibility Principle,SRP)
- 定义:
- 示例:
- 好处:
- 5、接口隔离原则(Interface Segregation Principle,ISP)
- 定义:
- 示例:
- 好处:
- 6、迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle)
- 定义:
- 示例:
- 好处:
- 7、合成聚合复用原则
- 更简单总结
1、开闭原则(Open - Closed Principle,OCP)
定义:
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着当需要对软件系统进行功能扩展时,应该通过添加新的代码(类、模块、函数等)来实现,而不是修改已有的代码。
示例:
以一个图形绘制系统为例,假设有一个绘制圆形的类CircleDrawer,如果要添加绘制矩形的功能,不应该直接修改CircleDrawer类。而是创建一个新的RectangleDrawer类来实现绘制矩形的功能。这样,在不修改已有CircleDrawer类的情况下扩展了系统的功能。
好处:
开闭原则可以提高软件系统的可维护性和可扩展性。因为修改已有的代码可能会引入新的错误或者影响到其他部分的功能,而通过添加新的代码来扩展功能可以将新功能的影响范围控制在新添加的部分。
2、里氏替换原则(Liskov Substitution Principle,LSP)
定义:
所有引用基类(父类)的地方必须能透明地使用其子类的对象。也就是说,子类对象应该能够替换父类对象,并且程序的行为和结果不会发生改变。
示例:
假设有一个基类Vehicle,有一个方法calculateSpeed()。有两个子类Car和Bicycle。根据里氏替换原则,在任何使用Vehicle类型对象来调用calculateSpeed()方法的地方,无论是使用Car对象还是Bicycle对象,都应该能够正确地计算出速度,并且不会导致程序出现错误或者不符合预期的行为。
好处:
里氏替换原则有助于保证程序的正确性和稳定性。它强制要求子类在继承父类时,不能改变父类原有的行为语义,从而避免了在多态调用时出现意外的结果。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
子类中可以增加自己特有的方法。
当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
子类不能覆盖父类的非抽象方法,降低耦合性,提高复用。
3、依赖倒置原则(Dependency Inversion Principle,DIP)
定义:
高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。简单来说,就是要面向接口编程,而不是面向具体的实现编程。
示例:
在一个电商系统中,高层的订单处理模块不应该直接依赖于低层的数据库存储模块。而是应该定义一个抽象的存储接口,订单处理模块依赖这个抽象接口,而数据库存储模块实现这个抽象接口。这样,如果要更换数据库存储方式(如从关系型数据库转换为非关系型数据库),只要新的存储模块实现了相同的抽象接口,就不会影响到订单处理模块。
好处:
依赖倒置原则可以降低模块之间的耦合度,提高系统的灵活性和可维护性。当系统的底层实现发生变化时,只要抽象接口不变,高层模块就不需要修改。
4、单一职责原则(Single Responsibility Principle,SRP)
定义:
一个类应该只有一个引起它变化的原因。也就是说,一个类应该只负责一项职责。
示例:
以一个用户管理系统为例,User类应该只负责与用户信息相关的操作,如获取用户姓名、年龄、修改用户密码等。而不应该同时负责用户登录验证的功能,登录验证应该由另一个专门的LoginValidator类来负责。这样,当用户信息的管理规则发生变化(如添加新的用户属性)时,只需要修改User类;当登录验证的方式发生变化(如添加验证码验证)时,只需要修改LoginValidator类。
好处:
单一职责原则可以使类的职责更加明确,提高类的内聚性,降低类的复杂度。这样在系统发生变化时,更容易定位和修改相关的代码,减少了因为一个类的职责过多而导致的代码修改风险。
5、接口隔离原则(Interface Segregation Principle,ISP)
定义:
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
示例:
假设有一个打印机接口Printer,包含了打印文档、扫描文档、传真文档等多个方法。但对于一个只需要打印功能的客户端(如一个简单的文本编辑器)来说,它不应该依赖包含扫描和传真功能的打印机接口。应该将打印机接口拆分成更小的接口,如Printable接口(只包含打印方法)、Scannable接口(只包含扫描方法)、Faxable接口(只包含传真方法),让客户端只依赖它需要的接口。
好处:
接口隔离原则可以避免客户端依赖不需要的接口,减少了接口的臃肿和客户端的负担。同时也提高了系统的灵活性和可维护性,因为当某个接口的功能发生变化时,只有依赖这个接口的客户端才会受到影响。
6、迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle)
定义:
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
示例:
在一个公司管理系统中,员工类Employee可能会使用部门类Department的一些信息。但是根据迪米特法则,Employee类不应该直接访问Department类的内部成员(如其他员工的信息),而是应该通过Department类提供的有限的接口(如获取部门经理的信息)来获取所需的信息。
好处:
迪米特法则可以降低类之间的耦合度,使系统的结构更加松散,提高系统的可维护性和可扩展性。因为一个类对其他类的了解越少,当其他类发生变化时,对这个类的影响就越小。
7、合成聚合复用原则
- (Composite/Aggregate Reuse Principle,CARP)也叫组合/聚合复用原则。它是面向对象设计原则之一,指的是尽量使用对象组合(has - a关系)或聚合(contains - a关系)而不是继承来达到软件复用的目的。
- 组合是一种强“拥有”关系,体现部分和整体的生命周期是一致的,例如鸟和翅膀,翅膀作为鸟的一部分,当鸟不存在时,翅膀也不存在了。聚合是一种弱“拥有”关系,部分可以独立于整体存在,例如雁群和大雁,大雁可以离开雁群独立生存。
-
与继承复用对比
- 继承复用的缺点
- 强耦合性:在继承关系中,子类与父类紧密耦合。例如,有一个基类“Vehicle(交通工具)”,它有两个子类“Car(汽车)”和“Motorcycle(摩托车)”。如果在Vehicle类中添加一个新的方法“repair(维修)”,那么Car和Motorcycle类都会继承这个方法。但如果Car类需要对“repair”方法有不同的实现,比如汽车维修可能涉及更多复杂的检查项目,就需要重写这个方法。这可能会导致代码在继承体系中频繁修改,而且一旦父类发生变化,子类可能会受到意外的影响。
- 缺乏灵活性:继承关系在编译时就已经确定,不能在运行时改变。比如一个基于继承的图形绘制系统,有基类“Shape(形状)”和子类“Circle(圆)”“Rectangle(矩形)”等。如果想要在运行时动态地改变一个形状对象从圆形变成矩形,使用继承就很难实现这种灵活的转换。
- 组合/聚合复用的优点
- 松耦合:组合和聚合关系使得各个类之间相对独立。以汽车为例,可以有一个“Engine(引擎)”类和一个“Car”类,它们通过组合关系关联。“Car”类拥有一个“Engine”类的对象作为其成员。如果“Engine”类的内部实现发生变化,比如改进了引擎的燃油喷射系统,只要“Engine”类对外提供的接口不变,“Car”类的代码基本不需要修改。
- 灵活性高:在运行时可以方便地改变组合或聚合的对象。例如,在一个游戏开发中,角色的武器是通过组合的方式添加到角色身上的。可以在游戏运行过程中,根据游戏情节的发展,为角色更换不同的武器,只需要重新组合武器对象和角色对象即可。
- 继承复用的缺点
-
应用场景示例
- 游戏开发中的道具系统:假设正在开发一款角色扮演游戏。有一个“Player(玩家)”类,玩家可以拥有不同的“Item(道具)”。“Player”类和“Item”类之间是聚合关系,因为玩家可以捡起或丢弃道具。可以通过在“Player”类中定义一个集合(如列表)来存储玩家拥有的道具。
-
遵循原则的好处
- 提高代码的可维护性:由于类之间的耦合度降低,当对某个类进行修改时,对其他类的影响范围较小。这样在维护代码时,更容易定位和解决问题。
- 增强代码的可扩展性:方便添加新的功能。例如在上述游戏道具系统中,如果要添加一种新的道具类型,只需要创建新的道具类并实现其功能,然后在玩家类中稍作修改(如果需要),就可以将新道具集成到游戏中,而不会对原有的游戏系统造成大规模的破坏。
- 提升代码的复用性:可以更好地复用已有的类。比如在不同的游戏场景或者不同的游戏角色中,可以复用“Item”类的各种道具,通过组合或聚合的方式将它们添加到不同的角色或场景中。
更简单总结
1、单一职责原则
定义:就一个类而言,应该只有一个引起该类变化的原因。
一个类只有一个职责,如果职责过多,代码就会臃肿,可读性更差,也更难以维护,主要体现面向对象的高内聚低耦合。
2、开闭原则(Open Close Principle)
定义:软件实体(类、模块、函数)应该可以扩展,但是不可修改。
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。
3、依赖倒转原则(Dependence Inversion Principle)
定义:高层模块不应该依赖于低层模块,两者都应该依赖于抽象;
抽象不应该依赖于细节,细节应该依赖于抽象;
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、里氏代换原则(Liskov Substitution Principle)
定义:子类型必须能替换掉它们的父类型。
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范,这个原则在工厂模式体现的比较明显。
5、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
6、迪米特法则,又称最少知道原则(Demeter Principle)
定义:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
简单来说就是一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立,还是体现了面向对象的高内聚低耦合。
7、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承
相关文章:

重温设计模式--2、设计模式七大原则
文章目录 1、开闭原则(Open - Closed Principle,OCP)定义:示例:好处: 2、里氏替换原则(Liskov Substitution Principle,LSP)定义:示例:好处&#…...

【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的?
【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的? 重要性:★★★ NLP Github 项目: NLP 项目实践:fasterai/nlp-project-practice 介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用…...
基于SSM(Spring + Spring MVC + MyBatis)框架构建一个图书馆仓储管理系统
基于SSM(Spring Spring MVC MyBatis)框架构建一个图书馆仓储管理系统是一个涉及多个功能模块的项目,包括但不限于图书管理、读者管理、借阅管理、归还管理等。 1. 环境准备 确保你已经安装了以下工具和环境: Java Developmen…...
web的五个Observer API
IntersectionObserver: 一个元素从不可见到可见,从可见到不可见 ??IntersectionObserver是一种浏览器提供的 JavaScript API,用于监测元素与视窗的交叉状态。它可以告诉开发者一个元素是否进入或离开视窗,以及两者的交叉区域的…...
Java基础:抽象类与接口
1、抽象类和接口的定义: (1)抽象类主要用来抽取子类的通用特性,作为子类的模板,它不能被实例化,只能被用作为子类的超类。 (2)接口是抽象方法的集合,声明了一系列的方法…...
llama.cpp:PC端测试 MobileVLM -- 电脑端部署图生文大模型
llama.cpp:PC端测试 MobileVLM 1.环境需要2.构建项目3.PC测试 1.环境需要 以下是经实验验证可行的环境参考,也可尝试其他版本。 (1)PC:Ubuntu 22.04.4 (2)软件环境:如下表所示 工…...
Web前端基础知识(一)
前端是构建网页的一部分,负责用户在浏览器中看到和与之交互的内容。 网页是在浏览器中呈现内容的文档或页面。 通常,网页使用HTML、CSS、JavaScript(JS)组成。 HTML:定义了页面的结构和内容。包括文本、图像、链接等。 CSS:定义页面的样式…...

基于谱聚类的多模态多目标浣熊优化算法(MMOCOA-SC)求解ZDT1-ZDT4,ZDT6和工程应用--盘式制动器优化,MATLAB代码
一、MMOCOA-SC介绍 基于谱聚类的多模态多目标浣熊优化算法(Multimodal Multi-Objective Coati Optimization Algorithm Based on Spectral Clustering,MMOCOA-SC)是2024年提出的一种多模态多目标优化算法,该算法的核心在于使用谱…...

国标GB28181摄像机接入EasyGBS如何通过流媒体技术提升安防监控效率?
随着信息技术的飞速发展,视频监控技术已成为维护公共安全和提升管理效率的重要手段。国标GB28181作为安防行业的统一设备接入与流媒体传输标准,为视频监控系统的互联互通提供了坚实的基础。EasyGBS作为一款基于GB28181协议的视频云服务平台,通…...

[Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
上次更新已然四个月前,零零散散的工作结束,终于有时间写点东西记录一下~ 实际使用中,经常会碰到同一个对象需要切换不同的材质,固然可以通过C#直接替换材质球。 或者在ShaderGraph中使用Comparison配合Branch实现切换ÿ…...

Unity开发哪里下载安卓Android-NDK-r21d,外加Android Studio打包实验
NDK下载方法(是r21d,不是r21e, 不是abc, 是d版本呢) google的东西,居然是完全开源的 真的不是很多公司能做到,和那种伪搜索引擎是不同的 到底什么时候google才会开始造车 不过风险很多,最好不要合资,风险更大 Andr…...
FFTW基本概念与安装使用
FFTW基本概念与安装使用 1 基本概念2 编译安装3 使用实例3.1 单线程3.2 多线程 本文主要介绍FFTW库的基本概念、编译安装和使用方法。 1 基本概念 FFTW (Fastest Fourier Transform in the West)是C语言的一个子程序库,用于计算一维或多维离散傅里叶变换(Discrete …...

【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
Hiヽ(゜▽゜ )-欢迎来到蓝染Aizen的CSDN博客~ 🔥 博客主页: 【✨蓝染 の Blog😘】 💖感谢大家点赞👍 收藏⭐ 评论✍ 文章目录 行为型模式1、模板方法模式(1)概述(2&…...

教师如何打造专属私密成绩查询系统?
期末的校园,被一种特殊的氛围所笼罩。老师们如同辛勤的工匠,精心打磨着每一个教学环节。复习阶段,他们在知识的宝库中精挑细选,把一学期的重点内容一一梳理,为学生们打造出系统的复习框架。课堂上,他们激情…...

【1224】C选填(字符串\0占大小,类大小函数调用,const定义常量,逗号表达式取尾,abs返回值
1.设有数组定义: char array[]"China"; 则数组array所占的存储空间为__________ 6 注意要加上\0的位置 数组中考虑‘\0’,sizeof()判断大小也要考虑‘\0’ 2.初始化数组char[] strArray"kuai-shou",strArray的长度为(&am…...
本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——终篇
本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——终篇 至此,本系列的所有备赛分享已经结束 首先说说备赛的过程吧,这次比赛,真的是让我学到了太多书本上学不到的东西。一开始,对统筹控制还很模糊&a…...

复合机器人:开启智能制造新时代
在当今科技飞速发展的时代,智能制造已成为制造业转型升级的关键驱动力。而复合机器人作为智能制造领域的一颗璀璨新星,正以其卓越的性能和创新的设计,为各行各业带来前所未有的变革与机遇。 复合机器人,顾名思义,是融…...

装饰者模式
代码详解:【设计模式】Java 设计模式之装饰者模式(Decorator)_java 装饰者模式-CSDN博客 // 抽象构件角色 public interface Component {void operation(); }// 具体构件角色 public class ConcreteComponent implements Component {Override…...

【机器学习】当教育遇上机器学习:打破传统,开启因材施教新时代
我的个人主页 我的领域:人工智能篇,希望能帮助到大家!!!👍点赞 收藏❤ 教育是人类社会发展的基石,然而传统教育模式往往难以满足每个学生的个性化需求。随着机器学习技术的兴起,教…...
【蓝桥杯每日一题】分糖果——DFS
分糖果 蓝桥杯每日一题 2024-12-24 分糖果 DFS 题目描述 两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。糖果必须全部分完。 只要有其中一个小朋友在两种方案中…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...

密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...