从坏味道到设计原则,构建灵活可维护的软件系统(《敏捷软件开发:原则、模式与实践》读书笔记)

news/2025/2/21 19:45:38/文章来源:https://www.cnblogs.com/Rong-/p/18725727

1. 软件设计中的坏味道(对应原书第7章)

核心理解:

  • 抽象不足:业务代码中掺杂过多细节,导致代码僵化、脆弱、难以理解和维护。
  • 业务逻辑应调用功能,而非实现功能:业务逻辑应通过调用功能接口来完成,而不是直接实现功能细节。
  • 功能抽象为接口,业务逻辑组合接口:功能应抽象为接口,业务逻辑通过组合和调度这些接口来实现。
  • 接口可扩展但不可修改:接口应保持稳定,允许扩展但不允许修改。
  • 功能实现可变,接口不可变:功能的实现可以灵活变化,但接口应保持稳定。
  • 优先调用库而非原始实现:尽量使用通用库(如STL、Boost),避免重复造轮子。

坏味道分类:

  1. 僵化性:设计难以修改,单一改动可能引发依赖模块的连锁反应。
    • 表现:实际工作量超出预期,未预料到的关联改动。
  2. 脆弱性:设计易于破坏,一个改动可能导致多个地方出现问题。
  3. 顽固性:设计难以重用,重用部分需要巨大努力和风险。
  4. 粘滞性:难以做正确的事情,保持设计的方法比临时拼凑更难。
    • 表现:编译时间长、源代码控制系统效率低。
  5. 不必要的复杂性:过度设计,包含当前无用的组成部分。
  6. 不必要的重复:滥用复制粘贴,忽视抽象。
  7. 晦涩性:模块难以理解,表达混乱。

2. 软件设计中的原则(对应原书第8、9、10、11、12、28章)

2.1 设计原则概览
序号 原则名称 缩写 英文全称 核心描述 对应设计模式
1 单一职责原则 SRP The Single Responsibility Principle 一个类(或接口)应只有一个发生变化的原因。 适配器模式(Adapter Pattern)、代理模式(Proxy Pattern)
2 开放-封闭原则 OCP The Open-Close Principle 软件实体(类、模块、函数等)应可扩展但不可修改。 策略模式(Strategy Pattern)、装饰者模式(Decorator Pattern)、观察者模式(Observer Pattern)
3 Liskov替换原则 LSP The Liskov Substitution Principle 子类型必须能够替换其基类型。 工厂模式(Factory Pattern)、模板方法模式(Template Method Pattern)
4 依赖倒置原则 DIP The Dependency-Inversion Principle 高层模块不应依赖低层模块,二者都应依赖抽象。 依赖注入(Dependency Injection)、服务定位器模式(Service Locator Pattern)
5 接口隔离原则 ISP The Interface Segregation Principle 为用户提供专用接口,避免强迫其依赖不需要的方法。 适配器模式(Adapter Pattern)、代理模式(Proxy Pattern)、装饰者模式(Decorator Pattern)
2.2 设计原则的价值与代价
序号 原则 违反的坏处 遵循的好处 代价
1 单一职责原则 代码复杂性增加、难以复用、高耦合性、测试困难 提高可维护性、增强可复用性、降低耦合性、简化测试 增加类的数量、初始设计复杂性、管理和组织难度、潜在的性能开销
2 开放-封闭原则 高风险修改、难以维护、影响其他功能 提高稳定性、增强灵活性、提高可维护性 设计复杂性增加、初始开发成本增加、可能的性能开销
3 Liskov替换原则 程序不稳定、难以维护、降低复用性 提高代码的灵活性和复用性、增强系统的稳定性、简化代码维护 设计复杂性增加、可能需要更多的抽象、初始开发成本增加
4 依赖倒置原则 高耦合、难以测试、降低灵活性 降低耦合度、提高可测试性、增强可扩展性 设计复杂性增加、初始开发成本增加、可能的性能开销
5 接口隔离原则 臃肿的接口、难以维护、降低灵活性 提高灵活性、增强可维护性、提高代码的可理解性 增加设计复杂性、初始开发成本增加、可能的代码冗余

个人理解:

  • 抽象带来自由:通过抽象隐藏实现细节,编写者和调用者都能获得更大的灵活性。
  • 抽象不足的代价:抽象不足会导致编写者和调用者都失去自由,代码难以维护和扩展。
  • 隐藏实现细节:将实现隐藏在接口后,编写者可以自由修改实现,调用者无需引入不必要的细节。
2.3 包和组件的设计原则
序号 分离 概述 原则名称 缩写 英文全称 描述
1 内聚性原则 帮助开发者决定如何将类划分到组件 重用-发布等价原则 REP Reuse-Release Equivalence Principle 重用的粒度就是发布的粒度
2 共同重用原则 CRP Common-Reuse Principle 一个组件中的所有类应共同重用
3 共同封闭原则 CCP Common-Closure Principle 组件中的所有类应对同一种变化共同封闭
4 组件耦合性原则 处理组件之间的关系,平衡可开发性和逻辑设计 无环依赖原则 ADP Acyclic-Dependencies Principle 组件之间的依赖关系不应形成循环
5 稳定依赖原则 SIP Stable-Dependencies Principle 依赖应朝向稳定的方向
6 稳定抽象原则 SAP Stable-Abstractions Principle 组件的抽象程度应与其稳定程度一致

3. 开发中的经验与教训

  • 避免重复犯错:将正确的代码封装为通用函数,避免重复错误。例如,StrTrim函数可以封装为通用工具函数。
  • 优先使用通用库:尽量使用通用库(如STL、Boost),避免重复造轮子。如果通用库中没有所需功能,可以自行开发通用库。

4. 总结

  • 抽象与接口的重要性:通过抽象和接口设计,可以显著提高代码的灵活性、可维护性和可复用性。
  • 设计原则的权衡:虽然遵循设计原则会增加初始设计的复杂性,但长远来看,能够显著提升代码质量和开发效率。
  • 识别与避免坏味道:通过识别和避免软件设计中的坏味道,可以有效提升代码的可读性和可维护性,降低后期维护成本。

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

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

相关文章

SynchronousQueue底层实现原理剖

一、SynchronousQueue底层实现原理剖 SynchronousQueue(同步移交队列),队列长度为0。作用就是一个线程往队列放数据的时候,必须等待另一个线程从队列中取走数据。同样,从队列中取数据的时候,必须等待另一个线程往队列中放数据 二、SynchronousQueue用法 先看一个Synchron…

[2025.2.18 JavaWeb学习]Mybatis

入门MyBatis是一款优秀的持久层(dao)框架,用于简化JDBC的开发 使用:IDEA创建SpringBoot模块,而后勾选MySQL Driver和MyBatis Framework pom.xml引入了mybatis-spring-boot-starter起步依赖、com.mysql依赖包、org.springframework.boot单元测试依赖 pojo中,创建实体对象,…

ROS2-PX4学习笔记

搞点小研究,欢迎对ROS2、PX4感兴趣的同学浏览。希望Mujica能好起来。ROS2-PX4学习笔记 前言 做毕设其实是个有点痛苦的过程。 毕竟所有东西都得现学,然后探索,时间又有限。 研究没接触过的新东西,总会失败,没有产出,搞久了人难受。 所以还是写一点东西吧。 我挺想把这个坑…

MessagePipe 中文文档

MessagePipe 是一个专为 .NET 和 Unity 设计的高性能内存/分布式消息管道。支持所有 Pub/Sub 场景、CQRS 中介模式、Prism 的 EventAggregator(视图与视图模型解耦)、IPC(进程间通信)-RPC 等。MessagePipeMessagePipe 是一个专为 .NET 和 Unity 设计的高性能内存/分布式消息…

Avalonia系列文章之样式与主题

随着社会的发展,大家对软件的要求,从最初的命令行输入输出,到可视化输入输出,如报表,图表等;从最初的可用性,稳定性为主,到现代软件理念中的便捷易用性转变,在保证稳定可用外,对软件的交互易用要求越来越高,而这些则离不开UI设计以及样式的应用。今天以一些简单的小…

SynchronousQueue的put方法底层源码

一、SynchronousQueue的put方法底层源码 SynchronousQueue 的 put 方法用于将元素插入队列。由于 SynchronousQueue 没有实际的存储空间,put 方法会阻塞,直到有消费者线程调用 take 方法移除元素 1、put 方法的作用将元素插入队列。如果没有消费者线程等待,当前线程会阻塞,…

【Tomcat文件上传】绕WAF姿势深入研究

环境 本地环境tomcat8.5.93,无黑白名单限制getSubmittedFileName()函数 tomcat可以通过filePart.getSubmittedFileName();获取上传文件的原始名filename获取Content-Disposition头后,判断值是否form-data或attachment开头 然后112行将form-data; name="file"; file…

关于一个手机控制电脑执行特定任务的解决方案探索【1】

【前言】 说来话长,关于这个手机控制电脑执行特定任务的想法早在几年前就有,但因为对安卓平台开发经验实在不足,就一直拖到了现在。不过好在没有忘记初衷,接下来我们一起来看我的思路和方法。 【思路】 想要通过手机作为控制端,来发送指令给同一网络下的电脑端,执行特定任…

如何升级 PowerShell 到最新版本

前言最近,需要大量使用PowerShell,然后有需要PowerShell 7正文升级的步骤也比较简单,按照下面的步骤就好了文字版本的,方便大家复制粘贴。PS C:\WINDOWS\system32> $PSVersionTable.PSVersionMajor Minor Build Revision ----- ----- ----- -------- 5 1 …

百万架构师第四十课:RabbitMq:RabbitMq-工作模型与JAVA编程|JavaGuide

来源:https://javaguide.net RabbitMQ 1-工作模型与Java编程 课前准备 预习资料 Windows安装步骤 Linux安装步骤 官网文章中文翻译系列 环境说明 操作系统:CentOS 7 JDK:1.8 Erlang:19.0.4或最新版 RabbitMQ:3.6.12或最新版 版本对应关系 典型应用场景跨系统的异步通信。人…

1月16日java假期学习读书笔记

一、学习目标 掌握HTML的基本结构和常用标签。 了解CSS的基本选择器和样式规则。 通过实际代码练习,构建一个简单的网页。 二、学习内容 (一)HTML基础 HTML简介 HTML(HyperText Markup Language,超文本标记语言)是用于构建网页的标准标记语言。 它通过一系列的标签(如、…

MapStruct使用指南并结合Lombok

MapStruct使用指南并结合Lombokhttps://juejin.cn/post/6956190395319451679#heading-1 2024-01-11 18:34:06如何结合 lombok 也就说说如果代码中使用了 lombok 注解来生成代码,mapstruct 的 getter/setter 方法也使用了 lombok 的 api,那就需要额外的配置,因为这两个工具都是使…