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

面向对象设计原则(一)

面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则。

单一职责原则

单一原则(Single Responsibility Principle,SRP)是最简单的设计原则,它用来控制类的颗粒度大小。
RoleDataOperation类承载了数据库连接、数据库数据操作、存档数据业务操作的功能职责,不符合单一职责。
下面来改进一下。

开闭原则

开闭原则(Open-Closed Principle ,OCP)是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。
在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类
开闭原则就是指软件实体尽量在不修改源码的情况下进行扩展。
开闭原则是评价基于某个设计模式设计的系统是否具备灵活性和可扩展性的重要依据。
下面来模拟一个刷怪塔
createMonster用如下实现代码
此时如果新增一种类型的怪物,那么必然会修改createMonster的业务逻辑,不符合开闭原则,下面来来修改一下。

里氏替换原则

如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1代换o2时,程序P的行为没有变化,那么类型S是类型T的子类型。
这个定义比较拗口且难以理解,因此我们一般使用它的另一个通俗版定义:所有引用基类(父类)的地方必须能透明地使用其子类的对象。
里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象
在程
序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
兼容LSP设计原则的execute方法
/ 创建Audio产品对象 Product* audio = new Audio(); audio->setFilePath("audio.mp3"); / 创建Video产品对象 Product* video = new Video(); video->setFilePath("video.mp4"); / 呼叫下载方法下载不同的产品 download(audio); download(video);
不兼容LSP设计原则
/ 创建Chocolate产品对象 Product* chocolate = new Chocolate(); chocolate->setFilePath("Chocolate can not be downloaded."); / 呼叫下载方法下载巧克力产品 download(chocolate);
TIP:现在的问题是谁应该对违反LSP负责?是download() 函数的创建者吗?是产品类的创造者吗?还是巧克力类的创造者?
TIP:常见的LSP违规
子类中的退化方法:如果基类有一个方法,但基类的子类不需要该方法,那么如果子类的作者再次
退化该方法,这将是可替代的违规。
从子类抛出异常LSP违规的另一种形式是向子类添加异常,而基类不希望这样。因为那时基类不能被子类替代。

依赖倒置原则

如果说开闭原则是面向对象设计的目标的话,那么依赖倒置原则(Dependence Inversion Principle,DIP)就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现。
依赖倒置原则定义如下:
高层模块不应该从低层模块导入任何东西,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应当依赖于抽象。
即:针对接口编程,而不是针对实现编程。
依赖倒置原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
在实现依赖倒置原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入
  • 构造注入是指通过构造函数来传入具体类的对象;
  • 设值注入是指通过Setter方法来传入具体类的对象;
  • 接口注入是指通过在接口中声明的业务方法来传入具体类的对象。
这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。
上面示例中DataBiz是典型的针对具体实现进行编程,因此在数据格式变更的时候就需要反复的修改代码。
下面进行重构。
基于依赖倒置原则,新增一个抽象的转换器DataConvertDataBiz针对DataConvert进行编程,然后根据里氏替换原则,程序运行时对父类进行替换,根据开闭原则,将运行对象指定设置到配置文件中。
在上述重构过程中,我们使用了开闭原则、里氏代换原则和依赖倒转原则,在大多数情况下,这三个设计原则会同时出现,开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段,它们相辅相成,相互补充,目标一致,只是分析问题时所站角度不同而已。

接口隔离原则

客户端不应该依赖哪些它不需要的接口。

根据接口隔离原则,当一个接口太大时,我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。
接口两种不同的含义:
  • 一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象。在ISP可以理解成一种角 色,一个接口只能代表一种角色,此时也可以称之为角色隔离原则
  • 一种是指某种语言具体的接口定义,有严格的定义和结构(如Java中的interface)。在ISP中表 达的意思是指接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提 供尽可能小的单独的接口,而不要提供大的总接口。

根据接口隔离原则重构

在使用接口隔离原则时,我们需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来很不方便。一般而言,接口中仅包含为某一类用户定制的方法即可,不应该强迫客户依赖于那些它们不用的方法。
组合复用原则
组合复用原则
http://www.cnnetsun.cn/news/2588645.html

相关文章:

  • 大规模二次规划与稀疏优化的分片线性同伦路径跟踪方法与分解技术【附代码】
  • 工业AOI实战:如何将HRIPCB数据集与YOLOv8结合,打造你自己的PCB缺陷检测系统
  • TwinGAN:双阶段GAN实现中国山水画风格迁移的技术解析与实践
  • 多Agent协同场景下的Harness工程架构设计与核心挑战破解
  • Arduino IDE 2.0调试器支持哪些板子?一份避坑清单与低成本替代方案
  • R语言non-numeric argument错误实战排障指南
  • HSGA模型:基于自引导注意力机制从临床文本预测疾病风险
  • RFDoc:面向证件检测的高效二进制局部特征描述符设计与实践
  • 最新Java面试趋势分析:哪些技能最吃香?
  • Cadence Concept HDL 17.4 保姆级开箱指南:从零新建你的第一个工程
  • HS2-HF Patch深度解析:构建HoneySelect2完整体验的生态解决方案
  • LangGraph 节点间数据传递的四种模式:参数、上下文、状态与缓存
  • PyInstaller打包进阶:除了UPX压缩,还有哪些优化exe体积的实用技巧?
  • 刚接触AI,适不适合直接学这个Agent平台?
  • RData实战:从高效保存到智能加载的完整工作流
  • 为什么产学研共建AI实验室,成了工业数据治理的必选项
  • Django 从 0 到 1 打造完整电商平台:数据库查询优化与索引
  • 极域电子教室UDP广播风暴治理三步法
  • 2026年怎么创建微信小程序
  • 双曲几何与对比学习驱动的MOOCs推荐:ROME框架原理与实践
  • 从零构建MATLAB GUI手写板:集成CNN模型实现实时数字识别
  • Go语言认证与授权机制详解
  • STM32F4系列ADC极限性能实战:从数据手册到代码配置(以STM32F407ZGT6为例)
  • Bootstrap 轮播组件详解
  • 避坑指南:R语言raster读取栅格时,na.rm参数没设置对,结果全变NA了怎么办?
  • pandas实战入门:从数据导入到工程化部署的完整闭环
  • CAXA 圆孔标记、孔标注、旋转符号
  • 影刀RPA店群自动化灾难恢复与业务连续性实战:备份、切换与数据丢失预防
  • 如何安全部署离线AI写作工具:3种终极方案详解
  • AD2019实心区域铺铜实战:从DCDC电源加固到阻焊开窗设置