【程序设计】一文讲解程序设计原则SOLDI

news2025/2/21 5:12:17

前言

设计原则,是指导我们如何设计出低耦合、高内聚的代码,让代码能够更好的应对变化,从而降本提效。

设计原则的关键,是从『使用方的角度』看『提供方』的设计,一句话概括就是:请不要要我知道太多,你可以改,但请不要影响我。


程序设计原则(SOLDI)

单一职责原则(SRP)

定义:一个函数/类只能因为一个理由被修改。

单一职责原则,是所有原则中看起来最容易理解的,但是真正做到并不简单。因为遵循这一原则最关键是职责的划分

职责的划分至少要回答两个基本问题:

  • 什么是你,什么是我?
  • 什么事情归你管,什么事情归我管?

且不说写代码,工作中我们也会出现人人不管或相争的重叠地带,划分清楚职责看起容易,实际很难。

开闭原则(OCP)

定义:对扩展开放,对修改关闭(不修改代码就可以增加新功能)。

要理解开闭原则,关键是要理解定义中隐含着的两个主语,“使用方”和“提供方”,即:

提供方可以修改,增加新的功能特性,但是使用方不需要被修改,即可享用新的功能特征。

开闭原则广泛的理解,可以指导类、模块、系统的设计,满足该原则的核心设计方法是:通过协议(接口)交互。

里氏替换原则(LSP)

定义:所有引用父类的地方,必须能透明的使用它的子类对象,指导类继承的设计。

面向对象的继承特性,一方面,子类可以拥有父类的属性和方法,提高了代码的复用性;另一方面,继承是有入侵性的,父类对子类有约束,子类必须拥有父类全部的属性和方法,修改父类会影响子类,增加了耦合性。

里氏替换原则是对继承进行了约束,体现在以下方面:

  • 子类可以实现父类的抽象方法,但不能重写(覆盖)父类的非抽象方法;
  • 子类可以增加父类所没有的属性和方法;
  • 子类重写父类方法时,输入参数类型要和父类的一致,或更宽松(参数类型的父类);
  • 子类重写父类方法时,返回值类型要和父类的一致,或更严谨(返回类型的子类)。

依赖倒置原则(DIP)

定义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象,目的是降低层与层之间的耦合。

从倒置来看,该原则可以有更泛化的理解:

  • 依赖实体的倒置:高层不依赖底层模块,抽象不依赖细节,例如模块分层规范中的domain不依赖infrastructure的实现;
  • 依赖控制的倒置:依赖具体对象的创建控制,从程序内部交给外部,例如Spring的Ioc容器。

举个购物车的例子:

  • 商业能力基座:主要包含购物车的业务流程实现、外域服务定义(非实现)、商业定制能力(扩展点),打包后需满足一套代码多处部署的要求。
  • 域服务能力实例:针对不同运行环境,提供适配环境的域服务实现,商业基座反向依赖域服务实例,使得基座与环境无关。

接口隔离原则(ISP)

定义:客户端不应该被强迫去依赖它并不需要的接口。

理解接口隔离原则,需要拿单一职责的原则做对比。细品一下,如果一个接口满足了

  • 单一职责,是否就也就满足接口隔离原则?
  • 单一职责原则,解决了接口内聚的问题。

接口隔离原则,认为某些场景下需要存在非内聚接口(多职责),但是又不希望客户端知道整个类,客户端只要知道具有内聚接口的抽象父类即可。

简单来讲,接口隔离原则解决的问题是,当某些类不满足职责单一原则时,客户端不应该直接使用它们,而是通过增加接口类,通过它隐藏客户端不需要感知到的部分。


项目实践

函数设计原则

有时候,优雅的实现仅仅是一个函数,不是一个类,不是一个框架,只是一个函数。—— John Carmack

(1)遵守的设计原则

单一职责。

  1. 短小:一个函数不超过50行代码,大量的setXXX()除外。
  2. 专一:一个函数只做一件事情,符合单一职责原则。

类设计原则

类是面向对象中最重要的概念,是一组关联数据的相关操作的封装,通常可以把类分为两种:
 

1)实体类:承载业务的核心数据和业务逻辑,命名要充分体现业务语义,比如Order/Buyer/Item。

2)辅助类:协调实体类完成业务逻辑,命名通常加后缀体现出其功能性,比如OrderQueryService/OrderRepository。

函数命名的关键点:

1)辅助类尽量避免用 Helper/Util 之类的后缀,因为其含义过于笼统,容易破坏单一职责原则。

2)针对某个实体的辅助操作过多,或单个操作很复杂,可通过 “实体 + 操作类型 + 功能后缀”来命名,同时符合职责单一和接口隔离的原则,比如OrderService:

  • OrderCreateService:订单创建服务;
  • OrderUpdateService:订单更新服务;
  • OrderQueryService:订单查询服务。

接口设计原则

接口分为第三方接口定义和应用内部接口定义。

1.第三方接口定义

(1)遵守的设计原则

在项目开发中,经常需要给第三方提供接口,第三方接口定义需要满足单一职责原则开闭原则

(2)接口定义建议

声明:

  1. 对于前端而言,后端web层接口属于第三方接口;
  2. 对于后端而言,后端调用其它服务的接口输液椅第三方接口。

此处,我主要是针对【后端】的第三方接口的讲解。

视角-接口类型(查询类与非查询类):

  1. 非查询接口:必须是幂等的,请求参数中应有requestId当做幂等id作为全局唯一标识。
    1. 幂等ID由上游提供,保证不同业务不同幂等ID。
    2. 通常由业务id充当幂等id,出问题时方便上下游通过幂等id找到确定是哪个业务出错。如订单编号、批次号...
  1. 查询类接口:大数据量查询必须提供分页操作,每页size不超过200条(dba强制:in语句在100条以内)。

视角-接口参数:

  1. 传参形式:推荐入参传递对象类型,而单个参数一个一个传递。反例:func(String param1, String param2)。原因:对象类型方便后面做扩展。
  2. 固定传参:如果是非查询类接口,参数中必须存在幂等ID。
  3. 参数类型:
    1. 浮点数(金额)必须使用BigDecimal,必须使用String构造方法。原因:防止精度丢失。
    2. 入参、出参不要使用枚举。推荐在这个字段上注释一个枚举类型。

2.内部接口定义

(1)遵守的设计原则

在项目开发中,经常需要给第三方提供接口,第三方接口定义需要满足单一职责原则开闭原则

(2)接口定义建议

主要关注点是如何做 功能扩展。

模块分层原则

模块分层


 

  • client:外部可见层(暴露服务声明);
  • service:业务逻辑层,对client层的实现,协调domain和infrastructure一起完成业务逻辑;
  • domain:领域层,对应DDD中的领域知识;
  • infrastructure:基础设施层,数据库访问、消息、外部调用等;
  • start:应用启动层,主要是项目启动时的静态配置。

模块内包分层

分包的建议:

  • 如果有多个一级域,建议:一级按业务分包,二级按功能分包,三级可按子领域分包。
  • 如果仅一个一级域,建议:一级按功能分包,二级按子领域分包。

例如:

|- xxx
|---- xxx-client             // 只提供仅需的外部依赖(DO不能再这层定义)
    |----biz1                // 子域module
        |----event           // 领域事件声明
        |----constant        // 常量(enum、final)
        |----dto             // 服务的出参对象,value object/view object
        |----request         // request or query
        |----service         // 本地/HSF服务接口声明
        |----facade          // 提供给Top/MTop的HSF接口
|---- xxx-domain             // 提供领域能力(entity、domainservice等)
    |----biz1                // 子域module
        |----factory         // 类工厂(构建器/转换器/工厂类)
        |----entity          // 充血模型的实体类
        |----service         // 领域服务
        |----repository      // api gateway 或 db repository接口,实现放在infrastructure
  |--test                    // 领域层单元测试
|---- xxx-infrastructure     // 基础设施层: mapper/config/repository impl
  |--main    
    |----biz1                // 子域module
        |----dataobject      // do: 贫血模型
        |----mapper          // mybatis mapper
        |----repository      // repository impl
  |--test                    // 基础设施层单元测试
|---- xxx-service            // 调用外域服务,使用domain层的能力
    |----biz1                // 子域module
        |----factory         // 类工厂(构建器/转换器/工厂类)
        |----service         // HSF服务接口实现
        |----facade          // 提供给Top/MTop的HSF接口实现,通常是调service的服务
        |----dts
        |----metaq
  |--test          // 服务实现层单元测试
|---- xxx-starter
  |--test            // 集成测试

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

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

相关文章

VBA技术资料MF36:VBA_在Excel中排序

【分享成果,随喜正能量】一个人的气质,并不在容颜和身材,而是所经历过的往事,是内在留下的印迹,令人深沉而安谧。所以,优雅是一种阅历的凝聚;淡然是一段人生的沉淀。时间会让一颗灵魂&#xff0…

IO流(2)-缓冲流

1. 缓冲流的简单介绍 我们上贴说到了 FileInputStream,FileOutputStream,FileReader,FileWriter。 其实这四个流,我们通常把它叫做原始流,它们是比较偏底层的;而今天我们要说的四个缓冲流,如…

自己创建的类,其他类中使用错误

说明:自己创建的类,在其他类中创建,报下面的错误(Cannot resolve sysmbol ‘Redishandler’); 解决:看下是不是漏掉了包名 加上包名,问题解决;

第9届Python编程挑战赛初中组初赛真题剖析-2023年全国青少年信息素养大赛

[导读]:超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲,这是超平老师解读Python编程挑战赛系列的第13讲。 全国青少年信息素养大赛(原全国青少年电子信息智能创新大赛)是“世界机器人大会青少年机器人设计与…

PyCharm安装pip依赖,如何添加国内镜像源?

目录 前言 PyCharm如何安装依赖 PyCharm如何配置国内镜像源 前言 首先我们都知道,使用pip安装依赖的方式,却很少有人知道使用PyCharm如何安装依赖。 PyCharm如何安装依赖 但你会发现,基本都是安装失败的,因为你是去外网下载的…

左神算法之中级提升班(8)

目录 【案例1】 【题目描述】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【案例5】 【题目描述】 【子序列概念】 【思路解析1 经典…

CTF-MISC:BUUCTF练习汇总(持续更新)

CTF-MISC:BUUCTF练习汇总 1、金三胖2、你竟然赶我走3、二维码4、大白 1、金三胖 解题思路: flag隐藏在gif图片帧中,使用在线GIF拆分工具即可 在线GIF图片帧拆分工具:https://uutool.cn/gif2img/ flag为:flag{he11oho…

应用层协议——https

文章目录 1. HTTPS 是什么2. 什么是"加密"3. 常见的加密方式4. 数据摘要 && 数字签名5. HTTPS 的工作过程探究5.1 方案1 - 只使用对称加密5.2 方案2 - 只使用非对称加密5.3 方案3 - 双方都使用非对称加密5.4 方案4 - 非对称加密 对称加密5.5 中间人攻击5.6 …

【MTI 6.S081 Lab】locks

【MTI 6.S081 Lab】locks Memory allocator (moderate)实验任务Hint解决方案 Buffer cache (hard)实验任务Hint解决方案数据结构设计初始化数据结构getrelse 本实验前去看《操作系统导论》第29章基于锁的并发数据结构,将会是很有帮助的。 在这个实验室中&#xff0…

懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒!

前言 系列首发gong zhong hao[『非同质前端札记』] ,若不想错过更多精彩内容,请“星标”一下,敬请关注gong zhong hao最新消息。 懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒! 何为代理模式 例如&#x…

倍增与ST算法

倍增与ST算法 倍增倍增原理倍增法的局限例题 :国旗计划 (洛谷 P4155)例题题解带注释的代码 ST算法ST算法原理ST算法步骤ST算法应用场合例题 :【模板】ST表 (洛谷 P3865) 倍增 倍增原理 倍增法的局限 例题 :国旗计划 (洛谷 P4155) 例题题解 带…

华为OD机试真题 Java 实现【报文回路】【2023 B卷 100分】,俗称“礼尚往来”

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、报文回路2、异常情况:3、解题思路 五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA&…

《JavaSE-第二十章》之线程的创建与Thread类

文章目录 什么是进程?什么是线程?为什么需要线程? 基本的线程机制创建线程1.实现 Runnable 接口2.继承 Thread 类3.其他变形 Thread常见构造方法1. Thread()2. Thread(Runnable target)3. Thread(String name)4. Thread(Runnable target, Str…

epoll复用

cli #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>// 服务器ip #define IP "192.168.250.100" // 服务器端口 #define PORT 8888int main…

c++11 标准模板(STL)(std::basic_ifstream)(一)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ifstream : public std::basic_istream<CharT, Traits> 类模板 basic_ifstream 实现文件流上的高层输入操作。它将 std::basic_istream…

Flink - souce算子

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 1. 从Java的集合中读取数据 2. 从本地文件中读取数据 3. 从HDFS中读取数据 4. 从Socket中读取数据 5. 从Kafka中读取数据 6. 自定义Source 官方文档 - Flink1.13 1. 从Java的集合中读取数据 …

二叉树(C语言)

文章目录 1.树1.1概念1.2相关定义1.3 表示&#xff08;左孩子右兄弟&#xff09; 2.二叉树2.1概念2.2特殊的二叉树1. 满二叉树&#xff1a;2. 完全二叉树&#xff1a; 2.3二叉树的性质2.4练习 3.二叉树的存储结构1. 顺序存储2. 链式存储 4.完全二叉树的代码实现4.1堆的介绍1.堆…

ssm德宏贸易项目java人资企业办公jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 ssm德宏贸易项目 系统有1权限&#xff1a;管理员 二…

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…

查询结果元数据-MetaData对象、数据库工具类的封装、通过反射实现数据查询的封装

六、查询结果元数据-MetaData对象 七、数据库工具类的封装 1、PropertieUtil类 2、DbUtil类 3、DBHepler类 查询&#xff1a; 4、TestDb测试类&#xff1a; 更新&#xff1a; 1&#xff09;插入&#xff1a; 2&#xff09;修改&#xff1a; 3&#xff09;删除&#xff1a; 查…