【再探】设计模式-设计原则

设计原则是在编写程序时引导程序员遵循的一些原则和准则。这些原则旨在提高代码的可读性、可维护性、可扩展性和可重用性。

  1. 可读性:理解和沟通的难易程度。
  2. 可维护性:修改和调整的难易程度。
  3. 可扩展性:应对未来变化的能力。
  4. 可重用性:资产的复用程度。

1 系统质量的衡量指标

1.1 高内聚低耦合

1.1.1 内聚

又称内联系,指模块内部各个元素(字段、方法等)彼此结合的紧密程度的度量。联系越紧密,则内聚性越高。

低内聚下,模块的功能可能不单一,模块的职责也不明确、可读性、扩展性很差。

偶然内聚

最低级别内聚。各成分之间没有关联,只是把分散的功能合并在一起。

逻辑内聚

执行功能上相似,可能会有些差异,但它们在逻辑上属于同一类。

例如鼠标和键盘,它们都属于输入模块。

时间内聚

这些方法需要在同一时间段内完成。

过程内聚

模块内各个元素都是为了完成同一个过程(可能并不直接相关于同一功能)而存在的,并按特定的顺序执行。

这使得代码结构更加清晰。

通信内聚

模块内元素通过共享数据或信息进行交流和协作,彼此依赖于共享的数据或信息来完成其功能。

顺序内聚

模块内元素不仅密切相关于同一功能,必须按照特定的顺序执行,美国处理元素的输出作为下一个处理元素的输入。

这确保来数据在模块内部按照预期的方式流动,从而实现了功能的连贯性和完整性,简化了代码的理解和维护,可能会导致模块间的耦合度较高。

功能内聚

模块内所以元素共同完成一个功能,缺一不可,且模块不能再切割。

表 七种内聚类型

1.1.2 耦合

模块之间的依赖关系越紧密,耦合度越高。修改一个模块就可能会影响到其他多个模块。

内容耦合

耦合度最大的一种形式,也被认为“病态耦合”。

一个模块不经调用直接使用另一个模块的内部数据或代码。有以下情形:

  1. 一个模块之间访问另一个模块的内部数据。
  2. 一个模块不通过正常入口进入到另一个模块内部。
  3. 两个模块有一部分代码重叠。
  4. 一个模块有多个入口。

公共耦合

不同模块引用了同一个全局数据。

外部耦合

模块与软件系统外部联系。例如数据库、硬件设备等。

控制耦合

一个模块调用另一个模块时,传递的是控制变量,被调用的模块会根据这个变量选择性地执行其内部功能。

标记耦合

两个模块之间通过参数传递对象,该对象的字段可以被视为标记。因为两个模块都可以对这个对象标记进行修改,因此耦合度相当较高。

数据耦合

耦合程度最低的一种类型,两个模块之间通过基本类型参数进行交互。

非直接耦合

模块之间没有直接相互调用关系,而是通过接口或者事件的方式进行通信。耦合度较低。

表 七种耦合类型

2 七大设计原则

2.1 单一职责

每个类应该只有一个职责,仅负责一个功能领域中的相应职责。

2.1.1 提出背景

当一个类职责过多时有以下缺点:

  1. 可读性差,类变得臃肿。
  2. 耦合度高,类与其他的类可能存在联系,当修改其功能时,可能会影响其他模块。
  3. 可维护性差,当修改其中一个职责时,可能会影响其他职责的运行。

2.1.2 优缺点

优点

  1. 提高类代码的可读性和可维护性。只负责一个特定职责,因此代码结构明了,易于理解和维护。
  2. 降低耦合度。类之间的关联和依赖减少,使得代码更加模块化和可重用。

缺点

  1. 类的数量增多,增加代码的复杂性。
  2. 过度拆分可能会降低性能。会导致在运行时需要创建很多的对象或进行更多的函数调用。

表 单一职责的优缺点

2.1.3 合理使用

1)识别并区分职责,确保每个类或方法只负责一个职责,并且这个职责时清晰明确的。

2)避免过度拆分,根据实际情况和需求来平衡类的数量和职责的划分。

2.2 开闭原则

是面向对象设计中最基础的设计原则,是接下来5种设计原则的基础。

主张一个软件实体(类、模块、函数等)应当对外扩展开发,对修改关闭。

核心思想是将可能变化的部分与不变的部分隔离开来,把变化的部分封装起来,而不变的则抽象为接口(面向接口编程)。

2.2.1 提出背景

不遵循开闭原则有以下缺点:

  1. 可维护性差,任何小的改动可能要直接修改现有代码,这不仅增加了出错的概率,也使得代码库变得越来越难易理解和维护。
  2. 可扩展性差,当需要添加新功能时,可能需要修改多个类或方法,可能会导致代码冗余和重复。
  3. 耦合度高,同时增加了测试难度和成本。
  4. 破坏封装性,可能会导致内部实现细节暴露给外部调用者。

2.2.2 优缺点

优点

  1. 可维护性好,所有的功能和特性都是基于抽象框架扩展而成,这使得各个功能特性之间保持独立且互不影响,后期维护目标明确。
  2. 扩展性好,可在不修改原有代码的基础上,基于抽象框架进行扩展。
  3. 可复用性好,抽象出来的部分具有共同特性,可以之间复用。

缺点

1)抽象难度较大,如果在初始阶段使用抽象构建的框架考虑不够全面,后期已扩展了很多功能特性时,一旦抽象框架发生变动,可能会影响下面的扩展部分。

表 开闭原则的优缺点

2.2.3 合理使用

1)明确抽象和具体实现,即区分变与不变的部分,将不变的部分抽象为接口或抽象类,而将变化的部分作为具体实现。

2)遵循单一职责原则,有助于识别并隔离可能变化的部分。

3)优先使用组合而非继承,通过组合,可以将对象视为黑盒子,只关心其提供的接口,而不必深入了解其内部实现。

2.3 里氏替换原则

子类必须能够替换其基类,且不会导致任何不期望的行为或错误。

子类可以扩展父类的功能,但不能改变其原有功能。不应该覆盖其非抽象方法,同时子类可以增加自己特有的方法。

2.3.1 提出背景

不遵循里氏替换原则的缺点:

  1. 破坏多态性,子类可能无法正确替换父类,限制了代码的灵活性和重用性。
  2. 破坏了封装性,使得父类的内部实现细节暴露给外部调用者。
  3. 可维护性差,开发者需要仔细跟踪每个子类对父类方法对覆盖情况,以确保它们的行为符合预期。
  4. 扩展性差,当需要添加新的功能或修改现有功能时,可能需要直接修改父类。

2.3.2 优缺点

优点

  1. 可维护性好,使得代码更模块化,有助于减少运行时错误。
  2. 可扩展性好,当需要修改或扩展时,可以通过添加新的子类来实现。
  3. 可复用性好,可以重用分类代码。

缺点

  1. 增加了设计的复杂性,需要对类的继承关系进行仔细的规划和设计,需要更多的时间来确保子类能正确地替换父类,并不会引入错误。
  2. 限制创新的灵活性,因为子类必须遵循父类的契约,可能需要放弃一些创新的想法和设计。
  3. 可能导致过度设计,可能会过度设计类的结构和关系,导致代码变得过于复杂和难以理解,会增加开发和维护的成本。

表 里氏替换原则的优缺点

2.3.3 合理使用

1)正确理解和使用继承,应当谨慎使用继承,避免滥用。过度使用可能会导致代码结构混乱,难以维护。

2)遵循契约设计,确保父类定义了一个明确的契约,即其方法和属性的预期行为和约束。如果子类需要改变父类的行为,应当考虑新的方法或属性,而不是直接覆盖父类的方法。

2.4 依赖倒转原则

高层模块不应该依赖低层模块,二者都应该依赖低层模块的抽象;抽象不应该依赖细节,细节应当依赖于抽象。

在代码中传递参数或搭建关联关系时,尽量使用接口和抽象类来代替具体类来进行变量类型声明、参数类型声明、方法返回类型声明等。

2.4.1 不遵循依赖倒转原则的缺点

1)可维护性差,高层模块依赖低层模块细节,如果底层模块细节做了修改,可能会影响其他模块。

2)可扩展性差,当添加新功能或支持新业务逻辑时,因为高层模块直接依赖底层模块的具体细节,这让扩展变得非常困难。

3)增加测试难度,模块之间的耦合度很高,当测试一个高层模块时,可能需要同时模拟和测试多个底层模块。

4)可重用性差,代码中可能会包含大量的具体实现细节,使得它难以在不同的场景或项目中进行重用。

2.4.2 优缺点

优点

  1. 降低耦合度,当底层模块发生变化时,高层模块不需要修改,只要底层模块仍符合抽象层的约定即可。
  2. 可维护性好,当需要修改或替换底层模块时,只需确保新的实现符合抽象层的接口即可,无需修改其他模块。
  3. 可扩展性好,只需实现新的抽象接口,就可将新功能集成到系统中。
  4. 重用性好,可以使得多个底层模块实现相同的接口。

缺点

  1. 增加抽象层,需要定义很多的接口或抽象类。
  2. 过度抽象,过度使用依赖倒转原则,会导致过多的抽象层,使得代码难以理解和维护。
  3. 性能影响,引入抽象层,可能在一定程度上影响程序的性能,尤其是需要频繁进行接口调用或类型转换的场景中。

图 依赖倒转原则优缺点

2.4.3 合理使用

1)识别并定义抽象,识别出系统哪些部分可以抽象化。

2)让高层模块依赖于抽象,通过抽象进行通信。

3)低层模块实现抽象,实现的细节应该隐藏在低层模块中。

4)避免过度抽象。

5)使用依赖注入等技术,在运行时将具体的实现类注入到需要它的高层模块中,从而实现高层模块与底层模块之间的解耦,容器管理依赖。

2.5 接口隔离原则

一个类对于另一个类的依赖应该建立在最小的接口上。(为各个类建立它们需要的专用接口,接口方法尽量细化)

2.5.1 不遵守接口隔离规则的缺点

1)可读性差,接口过于臃肿导致实现类的代码量增多。

2)可维护性差,内聚性可能比较松散,修改一个方法可能会影响其他方法。

3)耦合性高,与多个模块会相关联。一旦接口发生变更,所有依赖于该接口的客户端都可能需要进行相应修改。

4)可扩展性差,当需要扩展功能时,需要花费更多时间和精力来分析接口的结构和行为。

2.5.2 优缺点

优点

  1. 降低耦合度,通过细分接口,可以减少模块之间的依赖关系,从而降低系统整体的耦合度。
  2. 可扩展性及可维护性好,当需要添加新功能或修改现有功能时,可以通过定义新的接口或修改现有接口来实现,而不需要对整个系统进行大规模的修改。
  3. 可读性好,代码更加清晰、简洁。

缺点

  1. 接口数量增加,可能需要定义更多的接口。
  2. 过度拆分风险,导致接口过于细碎,增加系统的复杂性。也会使开发人员管理更多的接口,增加开发和维护的难度。

表 接口隔离原则的优缺点

2.5.3 合理使用

1)分析现有接口,拆分过于庞大或臃肿的接口,识别出接口中不同客户端可能不需要的方法。

2)保持接口独立性,美国小接口独立存在,不依赖其他接口的实现。

3)适度拆分,避免过度拆分导致数量过多,权衡接口拆分程度和系统的整体复杂性。

2.6 合成复用原则

尽量使用对象组合而不是继承来达到复用的目的。

2.6.1 不遵循合成复用原则的缺点

1)过度依赖继承,导致类层次结构变得庞大而复杂,使得理解和维护代码变得困难。

2)降低代码灵活性,继承意味着子类必须遵循基类的设计和实现,这限制了子类的灵活性和创新空间。

3)耦合度高,当基类发生变化时,所有子类都可能受到影响。

2.6.2 优缺点

优点

  1. 提高类灵活性,组合关系运行时可以动态地改变对象的行为,增加了系统的动态性。
  2. 降低耦合度,减少了类之间的依赖关系,对象之间通过接口或委托进行交互。
  3. 提高代码的复用性,通过复用已有的对象来构建新的对象。
  4. 可读性强,通过组合,可以将复杂的功能拆分成多个简单的对象,使得每个对象的功能更加单一和明确。

缺点

  1. 性能开销,组合可能需要更多的运行时开销,因为每个对象都需要吧单独创建和管理。
  2. 可能会增加系统复杂性,过度使用会导致结构变得复杂,包含大量的对象和交互关系。

表 合成复用原则的优缺点

2.6.3 合理使用

1)优先考虑使用组合而非继承关系来实现代码复用。

2)对象之间通过接口来引用。

3)适度复用,避免引入不必要的复杂性和性能开销。

2.7 迪米特法则

也成为最小知识原则。

一个对象对其他对象保持最少的了解,只需要知道与自己密切相关的类。

与自己密切相关的类包括:

  1. 当前对象本身。
  2. 以参数形式传入到当前对象方法中的对象。
  3. 当前对象的成员对象。
  4. 当前对象所创建的对象。

2.7.1 不遵循迪米特法则的缺点

1)高耦合低内聚,当一个类知道太多其他类的细节时,这些类之间就形成了紧密的耦合关系。同时它的内部功能就不再集中和一致,职责变得模糊。

2)性能下降,过多的类间通信和依赖关系导致性能下降,美国通信和依赖都可能引入额外的开销。

3)违反封装原则。封装强调对象的内部状态和行为隐藏起来,如果一个类知道其他类太多细节,那封装就被破坏了。

2.7.2 优缺点

优点

  1. 降低耦合度。
  2. 提高可扩展性。
  3. 促进代码重用。

缺点

  1. 增加通信开销。
  2. 设计难度增加。
  3. 可能过度设计。

表 迪米特法则的优缺点

2.7.3 合理使用

1)明确职责和接口,避免暴露过多的内部状态和方法,以减少外部类对其依赖。

2)减少直接依赖,通过中介者、代理或事件进行通信。

3)考虑性能和效率

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

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

相关文章

接收区块链的CCF会议--SecureComm 2024 截止5.10 附录用率

会议名称:SecureComm CCF等级:CCF C类会议 类别:网络与信息安全 录用率:2022年录用率33%(43/130) Topics Security and privacy in computer networks (e.g., wired, wireless, mobile, hybrid, sensor, vehicular,…

UI5:面向企业级应用的JavaScript框架

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

时间默认显示当前日期及系统时间

要将 xtdsSj 绑定到当前日期和系统时间&#xff0c;你可以在组件的 data 中初始化 xtdsSj 属性为当前日期及系统时间的字符串。然后&#xff0c;在组件创建时更新 xtdsSj&#xff0c;确保它始终显示当前日期和系统时间。 1.系统读数时间默认显示当前日期及系统时间 <templa…

斯坦福HAI年度报告增加AI4S;美阿贡国家实验室与日本最大综合研究机构建立合作;催化剂加获得深势科技未知金额投资

AI for Science 企业动态速览—— Cota Healthcare 与赛诺菲达成合作 腾讯牵头共建医疗影像国家新一代人工智能开放创新平台 催化剂加获得深势科技未知金额投资 TetraScience 与 Google Cloud 合作促进科学人工智能创新 美国阿贡国家实验室和日本理化学研究所签署谅解备忘录…

ng反向代理 conf配置

log_format szxw_timed_combined $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $request_time $upstream_response_time;#外部转发 …

15.Nacos服务分级存储模型

服务跨集群调用问题&#xff1a; 服务调用尽可能的选择本地集群的服务&#xff0c;跨集群调用延迟较高。 本地集群不可访问的情况下&#xff0c;再去访问其他集群。 如何配置集群的实例属性&#xff1a; spring: cloud:nacos:server-addr: localhost:8848 #nacos服务端地址d…

JMeter--逻辑控制器--仅一次控制器

仅一次控制器&#xff08;Once Only Controller&#xff09; 可以让控制器内部的逻辑只执行一次&#xff1b;单次的范围是针对某一个线程&#xff0c;无论线程外面迭代多少次或者里面循环多少次&#xff0c;均只执行一次&#xff1b;单次控制器一般可用于登陆&#xff…

springCloud是什么,怎么创建

Spring Cloud是一个微服务框架&#xff0c;它为微服务架构开发提供了全套的分布式系统解决方案。它利用Spring Boot的开发便利性&#xff0c;简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等。Spring Cloud并没有…

findImg找图工具

findImg 安装 npm install findImg -g 启动 findImg run 介绍 找出当前目录下的所有图片&#xff08;包括svg的symbol格式&#xff09;在浏览器中显示出来 源码 https://github.com/HuXin957/find-img 场景 例如前端项目中的img目录&#xff0c;大家都在往里面放图片&#xff…

java接口自动化测试

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

实验3 7段数码管译码器动态显示

实验目的: 1、构建基于verilog语言的8位7段断数码管的驱动实验; 2、掌握数码管的数显原理。 3、完成如下功能:8位数码管循环显示0123456789。 实验内容及步骤: 一、实验原理 1、数码管结构 当数码管特定的段加上电压后,这些特定的段就会发亮,以形成我们眼睛看到的…

那些早期的iax和SIP软电话软件界面,看看你见过几个?

目录 一些iax/sip软电话UI图片SIP软电话的界面怎么设计SIP软电话的功能有哪些 早期voip发展中&#xff0c;很多公司开发了自己的SIP软电话&#xff0c;有些已经不存在了&#xff0c;有些还在使用中&#xff0c;比如X-Lite&#xff0c;Zoiper等等&#xff0c;我们一起看看这些早…

Linux文本处理三剑客:awk、grep和sed

Linux文本处理三剑客&#xff1a;awk、grep和sed的完美结合 在Linux世界里&#xff0c;文本处理是一项至关重要的任务。无论是日常的系统管理还是复杂的软件开发&#xff0c;都需要对文本数据进行提取、过滤和转换。Linux为我们提供了三款强大的文本处理工具&#xff1a;awk、…

Environment Modules工具

Environment Modules工具 简介 Module是一个环境变量管理工具&#xff0c;可以很好的实现开发环境的切换。 具体可以查看官网文档 安装 安装&#xff08;安装完成之后需要exit重新登录一下才会生效&#xff09; yum install -y environment-modules命令介绍 module avai…

lvgl图形化设计工具GUI Guider结合使用

前言 上篇博客整合了lvgl到项目中&#xff0c;采用的是自己编写源码的方式&#xff0c;实现了个简单的界面。实际过程中一般情况开发界面都借助设计工具&#xff0c;这里使用的是gui guider来进行示例记录 项目结构&#xff08;生成代码路径依然放到项目路径下&#xff09; C…

分别用高斯消元法和列主元消去法求解,(自制)表格比较两种算法的结果与精度,分析实验出现的问题,并总结解决办法。

以下是一个使用高斯消元法和列主元消去法求解线性方程组的示例&#xff1a; 假设我们要解决以下线性方程组&#xff1a; 4x 2y z 8 -2x y - 3z -11 3x - 2y 4z 10 首先&#xff0c;我们可以将该线性方程组表示为增广矩阵的形式&#xff1a; [4 2 1 | 8] [-2 1 -3 | …

实验2 组合逻辑电路与时序逻辑电路设计

实验目的: 1.构建基于verilog语言的组合逻辑电路和时序逻辑电路; 2.掌握verilog语言的电路设计技巧。 3.完成如下功能:加法器、译码器、多路选择器、计数器、移位寄存器等。 实验内容及步骤: 一、实验原理 原理图文件《数字系统设计_sch.pdf》,找到如下两个部分: 图…

一文扫盲(5):实验室管理系统的界面设计

本次带来第5期&#xff1a;实验室管理系统的设计&#xff0c;从系统定义、功能模块、界面构成和设计着力点四个方面讲解&#xff0c;大千UI工场愿意持续和大家分享&#xff0c;欢迎关注、点赞、转发。 一、什么是实验室管理系统 实验室管理系统是一种用于管理和监控实验室运作…

nodejs版本过高导致vue-cli无法启动的解决方案

目录 前言异常现象解决方案总结 前言 之前使用软件管家升级了Nodejs&#xff0c;今天在运行Vue项目的时候老是报错&#xff0c;查了很多资料&#xff0c;最后确定是Nodejs版本过高导致的。 异常现象 E:\project\ry\RuoYi-Cloud\ruoyi-ui>npm run dev> ruoyi3.6.4 dev …

13-LINUX--消息队列

一.消息队列 1.消息队列&#xff1a;消息队列为一个进程向另一个进程发送一个数据块提供了条件&#xff0c;每个数据块会包含一个类型。 2.相关函数 1>.msgget(key_t key,int msgflg) : 创建消息队列 2>. msgsnd&#xff1a;把消息添加到消息队列 3>.msgrcv &#xf…