《设计模式之美》第五章 总结

发布于:2024-04-28 ⋅ 阅读:(23) ⋅ 点赞:(0)

《设计模式之美》第五章 总结

第五章 重构技巧

5.1 重构四要素:目的、对象、时机和方法

5.1.1 重构的目的:为什么重构
定义:重构是一种对软件内部结构的改善,目的是在不改变软件对外部的可见行为的情况下,使其更容易理解,修改成本更低;
目的:
1. 保证代码质量的有效手段;
2. 可有效避免代码质量下滑;
3. 避免代码过度设计的有效手段;
4. 是设计原则、设计模式、代码规范等伦理知识的重要应用场景;
5. 衡量软件工程师的编码能力的重要手段;

初级工程师开发代码(在代码框架下写代码),高级工程师设计代码(设计代码结构、搭建代码框架),资深工程师重构代码(为代码质量负责,保证代码质量处于可控状态);
5.1.2 重构的对象:到底重构什么
大规模高层次重构:
内容:系统、模块、代码结构、类之间关系;
手段:分层、模块化、解耦、抽象可复用组件(设计原则、设计模式);
小规模低层次重构:
内容:类、函数、变量等
手段:代码规范;
5.1.3 重构的时机:什么时候重构
方案:持续重构;
5.1.4 重构的方法:应该如何重构
大型重构:
1. 提前制定完善的重构计划,有条不紊地分阶段进行;每个阶段完成一小部分代码的重构,然后提交、测试和运行,没问题之后,再进行下一阶段的重构,保证代码仓库中的代码一直处于可运行的状态;
2. 每个阶段都要控制重构影响的代码的范围,考虑如何兼容旧的代码逻辑,必要时提供实现兼容的过度代码;
3. 每个阶段最好一天就能完成;
4. 是一个有组织的、有计划的、谨慎的,需要经验丰富、业务熟练的资深工程师主导;
小型重构:
影响范围小,耗时短,随时可以进行;
重构工具:代码分析工具自动发现代码中存在的问题;

5.2 单元测试:保证重构不出错的有效手段

手段:熟练掌握经典的设计原则和设计模式,还要对业务和代码有足够的了解、单元测试;
5.2.1 什么是单元测试
需要程序员思考缜密,设计尽量覆盖所有正常情况和异常情况的测试用例,保证代码在任何预期和非预期的情况下都能正确运行;
5.2.2 为什么要进行单元测试
提高代码质量的有效手段:
1. 帮助程序员发现代码中的bug
2. 发现代码设计上的问题
3. 对集成测试的有利补充:可以模拟异常情况、复杂的情况,集成测试无法覆盖的情况
4. 编写单元测试的过程就是重构的过程:相当于做一次codeReview,可以发现代码的问题
5. 帮助程序员快速熟悉代码
6. 是TDD(测试驱动开发)的改进方案
5.2.3 如何设计单元测试
方法:针对代码设计覆盖各种输入、异常和边界条件的测试用例,将测试用例翻译成代码;
判定单元测试的质量:单元测试能够自动化运行,不需要人工干预(如准备数据),不会因为运行环境的变化而失败,就是合格的;
覆盖率计算:简单语句的覆盖,复杂一些的条件覆盖、判定覆盖、路径覆盖;
一般覆盖率到60~70%就可以上线了;
5.2.4 为什么单元测试落地困难
1. 考验耐心
2. 开发任务紧
3. 历史原因

5.3 代码的可测试性:如何编写可测试代码

5.3.1 编写可测试代码的方法
一个类的单元测试代码是否容易编写的关键性在于这个类的独立性,也就是这个类是否满足“高内聚、低耦合”特性;
如果类和其他类的耦合度高,甚至与第三方系统也有耦合(比如数据库、RPC调用等),那么这个单元测试会很难写;
依赖注入的作用是降低代码耦合度,是提高代码可测试性的有效方法;
5.3.2 常见不可测试代码的示例
1. 未决行为:指输出是随机的或不确定的,多与时间、随机数有关;
2. 全局变量:
3. 静态方法:因为静态方法很难Mock,只有在静态方法执行时间过长、依赖外部资源、逻辑复杂和行为未决等情况下我们才需要在单元测试中Mock静态方法;
4. 复杂的继承关系:继承的类之间继承关系太复杂,耦合度太高,层次越深需要Mock的对象越多;	

5.4 解耦:哪些方法可以用来解耦代码

5.4.1 为何解耦如此重要
如何控制代码复杂度:显著有效的手段是解耦;
解耦的作用:使代码高内聚、低耦合;
高内聚、低耦合:一种通用的设计思想,可以用在类之间、系统、架构、模块的设计,可以在更高的层次上提高代码的可读性和可维护性;
高内聚、低耦合的作用:可以让我们聚焦在某一模块或类,降低阅读和修改代码的难度;因为依赖关系简单、耦合度低,所以修改代码时不会牵一发而动全身,代码改动集中,引入bug的风险降低;
意味着:代码结构清晰,分层和模块化合理,依赖关系简单,模块或类之间的耦合度低,修改代码影响的范围有限,进行小型重构的难度大幅降低;
5.4.2 如何判定代码是否需要解耦
1. 改动代码出现牵一发而动全身的情况;
2. 根据模块之间、类之间的依赖关系图的复杂度来判断;
5.4.3 如何给代码解耦
1. 通过封装与抽象来解耦:封装和抽象可以有效隐藏实现的复杂性,隔离实现的易变性,给上层模块提供稳定的接口;
2. 通过引入中间层来解耦:可以简化模块之间或类之间的依赖关系;中间层可以起到过渡作用
	引入中间层的重构方式:
	第一阶段:引入一个中间层,利用中间层“包裹”旧接口,提供新接口;
	第二阶段:新开发的代码依赖中间层提供新的接口;
	第三阶段:将依赖旧接口的代码改为调用新接口;
	第四阶段:确保所有代码都调用新接口之后,删除就接口;
	可以使重构分阶段完成;
3. 通过模块化、分层来解耦:
	模块化是构建复杂系统的常用手段,本质是:分而治之;
	面对复杂系统的开发,善于用分层技术,尽量将容易复用、与具体业务关系不大的代码下沉到下层,将容易变动、与具体业务强相关的代码移到上层;
4. 利用经典的代码设计思想和设计原则来解耦
	1. 单一职责原则:实现高内聚的指导原则;如果模块或类的职责单一,它们依赖的类或依赖它们的类较少,代码的耦合度也就降低;
	2. 基于接口而非实现编程:有依赖之间的模块或类之间的改动不会互相影响;
	3. 依赖注入:减弱耦合
	4. 多用组合、少用继承:
	5. LoD:

5.5 重构案例:将ID生成器代码从“能用”重构为“好用”

5.5.1 ID生成器需求背景
5.5.2 “凑合能用”代码的实现
5.5.3 如何发现代码的质量问题
1. 模块划分是否清晰?代码结构是否满足“高内聚、低耦合”特性?
2. 代码是否遵循经典的设计原则
3. 设计模式是否应用得当?代码是否存在过度设计问题?
4. 代码是否易扩展?
5. 代码是否可复用?是否有“重复造轮子”现象?
6. 代码是否容易进行测试?单元测试是否全面覆盖了各种正常和异常情况?
7. 代码是否符合代码规范(如命名和注释是否恰当,代码风格是否统一等)?
可以把上面这些点作为常规检查项;
与业务相关的检查项:
1. 代码是否实现了预期的业务需求;
2. 代码逻辑是否正确?代码是否处理了各种异常情况?
3. 日志输出是否得当?
4. 接口是否易用?接口是否支持幂等、事务等?
5. 代码是否存在线程安全?
6. 代码的性能是否有优化空间?
5.5.4 第一轮重构:提高代码的可读性
5.5.5 第二轮重构:提高代码的可测试性
5.5.6 第三轮重构:编写单元测试代码
5.5.7 第四轮重构: 重构异常处理逻辑

网站公告

今日签到

点亮在社区的每一天
去签到