软件开发的六大设计原则

news2024/11/24 1:49:42

我们常说软件开发要尽量具有良好的可扩展性,做到高内聚低耦合。那么究竟该如何实现呢?在面向对象软件设计领域有一系列大家所认可的设计原则,依据这些原则来设计软件,就可以让软件有很好的可扩展性,其中最重要的一条原则就是开闭原则,其他原则可以说都是以开闭原则为基础的。
在这里插入图片描述

开闭原则是软件设计原则的基础

开闭原则

Bertrand Meyer

开闭原则(Open-Closed Principle, OCP)是最重要的面向对象设计原则,由Bertrand Meyer于1988年提出:

一个软件实体应当对扩展开放,对修改关闭。

软件实体应尽量在不修改原有代码的情况下进行扩展。

其中软件实体可以是指一个软件模块、一个由多个类组成的结构或者是一个独立的类。

任何软件都面临一个问题,就是它们的需求会随着时间的推移而发生变化。当软件系统要面对新的需求时,应当尽量保证系统的整体框架是稳定的,不会有大的改变。

如果一个软件设计符合开闭原则,那么就比较容易对系统进行扩展,软件系统在具有适应性和灵活性的同时,也具备较好的稳定性和延续性。

为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java、C#、C++等OOP编程语言中,都提供了接口、抽象类等抽象化的语言机制,通过它们可以定义软件的抽象层,再通过具体的实现类来扩展。如果要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的功能即可。

单一职责原则
单一职责原则(SRP:Single Responsibility Principle)是最简单的面向对象设计原则,它用于控制类的粒度大小。定义如下:

一个类只负责一个功能领域中的职责,或者可以这样说,就一个类而言,应该只有一个引起它变化的原因。

在软件系统中,一个类承担的功能越多,被复用的可能性就越小,这些功能耦合在一起,当其中一个发生变化时,还可能会影响其他功能。因此要将功能分离,除非多个功能总是同时发生变化,才可将它们封装在同一个类中。

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员具有较强的分析设计能力和实践经验。这个原则不仅是针对类的设计,在微服务架构中,同样适用于服务的功能划分。不要把不相关领域的功能都放在同一个服务中。

里氏替换原则
在这里插入图片描述

图灵奖得主Barbara Liskov教授

里氏代换原则(LSP: Liskov Substitution Principle)由2008年图灵奖得主Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出。其定义如下:

所有引用基类(父类)的地方必须能透明地使用其子类的对象。

里氏代换原则要求:在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,但反过来则不成立。

由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

依赖倒转原则
依赖倒转原则(DIP: Dependency Inversion Principle)是OOP设计的主要实现机制之一,由Robert C. Martin在1996年提出。定义如下:

抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

在这里插入图片描述

高层模块只针对接口编程,不依赖低层模块

在实现依赖倒转原则时,我们需要针对抽象层编程,将具体类的对象通过依赖注入(DI: Dependency Injection)的方式注入到其他对象中。

常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

5 接口隔离原则
接口隔离原则(ISP:Interface Segregation Principle)与单一职责原则类似,只不过单一职责原则说的是类,接口隔离原则说的是接口。其定义如下:

使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

当一个接口太大时,我们需要将它分割成一些更细小的接口。每一个接口应该承担一种相对独立的角色,不该干的事不干,该干的事都要干。

6 迪米特原则
在这里插入图片描述

适配器模式就是LoD原则的一种体现

迪米特原则(LoD:Law of Demeter)来自于1987年美国东北大学(Northeastern University)一个名为“Demeter”的研究项目。迪米特法则又称为最少知识原则(LKP:Least Knowledge Principle),其定义如下:

只和朋友交流,不和陌生人说话。也就是说,一个软件实体应当尽可能少地与其他实体发生相互作用。

如果一个系统符合迪米特法则,那么当其中某一个模块发生修改时,就会尽量少地影响其他模块,扩展就会相对容易,这是对软件实体之间通信的宽度和深度的限制,通过限制交互可降低系统的耦合度,使类与类之间保持松散的耦合关系。

总结
掌握这些软件开发的设计原则,对我们开发高内聚、低耦合的系统是非常有帮助的。互联网系统的功能迭代非常频繁,如果在软件设计阶段就做好足够的扩展性设计,那么后面的功能修改都会变得更加容易,上线发布的周期也会大大缩短。千万不要为了赶进度,牺牲了扩展性设计,还是要尽量多花点时间在设计上。

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

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

相关文章

发起投票平台投票吧网络投票平台网络投票平台

小程序投票活动如何做?很多企业在运营当中,都会通过投票活动来进行推广,从而达到吸粉、增加用户粘度等效果。而此类投票活动,通过小程序就可以实现,操作简单。 我们现在要以“青春大不同”为主题进行一次投票活动&…

扩展欧几里得 证明及应用代码(超详细,附带例题)

应用方面: 1.求解乘法逆元 2.求解(ax)%bc 即 a个x 模上b后得到c,其中满足条件的x的最小整数。[也可表示为axc(mod b)] 3.求解直线上的整点数 模板代码: 代码1: ll exgcd(ll a,ll b,ll &x,ll &a…

jeecgboot:vue3版本打包失败的解决过程

根据jeecgboot vue3的文档,把本地node升级到16,在本地运行都正常,打包后一直提示内存不足。 首先怀疑是代码配置问题,找到提示对应的地方,修改了package.json,把默认的NODE_OPTIONS--max-old-space-size81…

【批量将视频转为图像序列】

批量将视频转为图像序列 代码如下,代码中带有解释: # 导入所需要的库 import cv2 import os import numpy as np# 多个视频所在的路径 datasets_path ["/home/y/Code/数据集/1/007f.mp4","/home/y/Code/数据集/1/05f.mp4","/…

Python 打印文件执行路径和行号

文章目录 前言代码部分演示意外惊喜,文件位置跳转 前言 我最近在学Python,但是我感觉动态语言如果不打印文件路径和行号,到时候如果出问题Debug,除非你对业务特别熟悉,不然找不到问题的位置。 反正打印了也不亏 代码…

合宙Air001开发板系列教程—01环境搭建与点灯(基于Keil-MDK的开发)

近日合宙出品了一款: TSSOP20封装、ARMCortex-M0内核,内置32K Flash4K RAM、集成多路USART、IIC、SPI等通讯外设,5个16bit定时器以及1路12bit ADC和2路比较器的国产MCU10块钱一个开发板10个芯片,性价比还是很高的,加其…

基于ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升技术

空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化:地图符号与注记 2.4 研究区…

ndk编译jni错误LOCAL_MAKEFILE is not defined,分析解决

概述 我们用ndk编译jni的时候,通常会写一个Android.mk脚本文件。但是有些情况,我们脚本文件名字不叫Android.mk,比如我的分别改成AndroidSo.mk,AndroidA.mk 这时候就会报错:LOCAL_MAKEFILE is not defined 软件环境 …

单片机数码管

LED数码管(LED Segment Displays)是由8个发光二极管构成,并按照一定的图形及排列封转在一起的显示器件。其中7个LED构成7笔字形,1个LED构成小数点(固有时成为八段数码管)。 LED数码管有两大类&#xff0c…

从新手到高阶,企业培训直播玩法全攻略

首先,把握培训直播的整体规划。 管理端:直播内容管理纳入企业内部学习资源的建设,让企业内部的知识积累、沉淀形成体系。学员端:方便学员精准、快速定位到课程资源,方便快捷检索内容,学习体验简单易用。 其…

CP AUTOSAR中的EThTrcv

环境 EthTrcv驱动实际上是要实现EthIf指出的接口,包括如下API函数,描述在一个结构体里面 /** \brief type used in EthIf_EthTrcvDrvApi */ typedef struct sEthIf_EthTrcvDrvApiType { EthIf_EthTrcvCheckWakeupFctPtrType CheckWakeupOfEthTrcvDrvApi; /**< Et…

2023 JAVA 面试太难, 吃透这份 JAVA 架构面试笔记后, 成功涨到 30K

前阵子跟一位高级架构师的前辈聊天时&#xff0c;聊到今年的面试。有两个感受&#xff0c;一个是今年面邀的次数比往年要低不少&#xff0c;再一个就是很多面试者准备明显不足。不少候选人能力其实不差&#xff0c;进入团队干活后达到期望不难&#xff0c;但由于没准备或不会表…

Python从入门到精通:一步步掌握Python编程

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言Python入门条件和循…

使用Django数据库模型中的ForeignKey()形成数据表记录的父子层次结构

可以把ForeignKey()的第1个参数设置为值 “self” 实际形成数据表记录的父子层次结构。 下面是一个简单的实例&#xff1a; 在文件 E:\Python_project\P_001\myshop-test\myshop\app1\models.py 中写入下面的代码&#xff1a; from django.db import models# Create your mod…

如何保证消息的可靠性+延迟队列(TTL+死信队列+延迟队列)

目录 1.如何保证消息的可靠性 1.1.消息的可靠投递 confirm机制 return机制 1.2.如何保证消息在队列中不丢失 1.3.确保消息能可靠的被消费掉 2.延迟队列 2.1.TTL 2.2.死信队列 2.3.延迟队列 3.如何防止消费者重复消费消息 1.如何保证消息的可靠性 1.1.消息的可靠投递…

element-ui 使用 el-descriptions

<el-descriptions :column"2" border size"mini" style"margin-top: 10px;" :labelStyle"{width: 123px}" :contentStyle"{width:42%}"><el-descriptions-item label"选择项目"><el-select size&…

花了整整一周,用新工具制作的进销存管理系统,比买来的好用

进销存简单点说就是进货、库存、出货的管理&#xff01;复杂一点还会牵扯日常交易。一般情况下&#xff0c;中小型企业或者涉及仓库的商贸、电商、制造、批发、零售等相关行业都会用到。 看似很简单&#xff0c;但涉及的领域却很广泛。 那么如何有效的管理企业的进销存数据&am…

UWB定位算法对比:TDOA算法和TWR算法对比,两种算法优缺点分析

UWB定位是基于时间飞行的算法&#xff08;飞行时间&#xff0c;TOF&#xff09;。测量一个UWB定位标签和多个UWB定位基站之间的光传播时间。至少需要三个定位基站才能使用三边法精确定位标签的位置。UWB定位基站和定位标签之间也必须保持直线和可视无遮挡。在UWB定位中&#xf…

Python源码剖析:深度探索Cpython对象-达观数据

CPython 是 Python 社区的标准&#xff0c;其他版本的 Python&#xff0c;比如 pypy&#xff0c;都会遵行 CPython 的标准 API 实现。想要更深入的认识 Python&#xff0c;就需要了解 CPython 的源码实现。本文将从 CPython 的对象构造器开始入手&#xff0c;带大家揭开 CPytho…

工作有感:莫名的IT培训班生涯

欢迎关注博主 六月暴雪飞梨花 或加入【六月暴雪飞梨花】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术…