(4)设计模式
文章目录
- 1. 为什么要重构(why)
- 2. 重构什么(what)
- 3. 什么时候重构(when)
- 4. 如何重构(how)
- 5. 保证重构不出错,落地的技术手段--单元测试
- 5.1 什么是单元测试
- 5.2 为什么要写单元测试
- 6. 可测试性代码
- 6.1 代码的可测试性
- 6.2 编写可测试性代码的最有效手段
- 6.3 常见的测试性不好的代码
- 7. 解耦
- 7.1 解耦为何很重要
- 7.2 代码是否需要解耦
- 7.3 如何给代码解耦
1. 为什么要重构(why)
重构是一种对软件内部结构的改善,目的是在不改变软件的可见行为的情况下,使其更易理解,修改成本更低。
- 首先,重构是时刻保证代码质量的一个极其有效的手段,不至于让代码腐化到无可救药的地步。
- 其次,优秀的代码或架构不是一开始就能完全设计好的,就像优秀的公司和产品也都是迭代出来的。
- 最后,重构是避免过度设计的有效手段。
重构实际上是对经典设计思想、设计原则、设计模式、编程规范的一种应用。构能力也是衡量一个工程师代码能力的有效手段。所谓“初级工程师在维护代码,高级工程师在设计代码,资深工程师在重构代码”。
2. 重构什么(what)
可以笼统地分为大规模高层次重构(简称为“大型重构”)和小规模低层次的重构(简称为“小型重构”)。
大型重构指的是对顶层代码设计的重构,包括:系统、模块、代码结构、类与类之间的关系等的重构,重构的手段有:分层、模块化、解耦、抽象可复用组件等等。
小型重构指的是对代码细节的重构,主要是针对类、函数、变量等代码级别的重构,比如规范命名、规范注释、消除超大类或函数、提取重复代码等等。小型重构更多的是利用编码规范。
3. 什么时候重构(when)
提倡的重构策略是持续重构。尽管说重构能力很重要,但持续重构意识更重要。
4. 如何重构(how)
对于大型重构来说,因为涉及的模块、代码会比较多,如果项目代码质量又比较差,耦合比较严重,往往会牵一发而动全身,在进行大型重构的时候,要提前做好完善的重构计划,有条不紊地分阶段来进行。每个阶段完成一小部分代码的重构,然后提交、测试、运行,发现没有问题之后,再继续进行下一阶段的重构,保证代码仓库中的代码一直处于可运行、逻辑正确的状态。每个阶段,都要控制好重构影响到的代码范围,考虑好如何兼容老的代码逻辑,必要的时候还需要写一些兼容过渡代码。只有这样,才能让每一阶段的重构都不至于耗时太长(最好一天就能完成),不至于与新的功能开发相冲突。
小规模低层次的重构,因为影响范围小,改动耗时短,所以,只要愿意并且有时间,随时都可以去做。实际上,除了人工去发现低层次的质量问题,还可以借助很多成熟的静态代码分析工具(比如 CheckStyle、FindBugs、PMD),来自动发现代码中的问题,然后针对性地进行重构优化。
要防止出现“破窗效应”。
5. 保证重构不出错,落地的技术手段–单元测试
5.1 什么是单元测试
单元测试相对于集成测试(Integration Testing)来说,测试的粒度更小一些。集成测试 的测试对象是整个系统或者某个功能模块,比如测试用户注册、登录功能是否正常,是一种端到端(end to end)的测试。而 单元测试 的测试对象是类或者函数,用来测试一个类和函数是否都按照预期的逻辑执行,是代码层级的测试。
5.2 为什么要写单元测试
单元测试除了能有效地为重构保驾护航之外,也是保证代码质量最有效的两个手段之一。
- 单元测试能有效地帮你发现代码中的 bug。
- 写单元测试能发现代码设计上的问题。
- 单元测试是对集成测试的有力补充。
- 单元测试的过程本身就是代码重构的过程。
- 阅读单元测试能帮助你快速熟悉代码。
- 单元测试是 TDD 可落地执行的改进方案。
JaCoCo、Cobertura、Emma、Clover可做覆盖率统计。
6. 可测试性代码
6.1 代码的可测试性
所谓代码的可测试性,就是针对代码编写单元测试的难易程度。对于一段代码,如果很难为其编写单元测试,或者单元测试写起来很费劲,需要依靠单元测试框架中很高级的特性,那往往就意味着代码设计得不够合理,代码的可测试性不好。
6.2 编写可测试性代码的最有效手段
依赖注入是编写可测试性代码的最有效手段。通过依赖注入,在编写单元测试的时候,可以通过 mock 的方法解依赖外部服务,这也是在编写单元测试的过程中最有技术挑战的地方。
6.3 常见的测试性不好的代码
- 未决行为。所谓的未决行为逻辑就是,代码的输出是随机或者说不确定的。
- 全局变量。
- 静态方法。
- 复杂继承。
- 高耦合代码。
7. 解耦
7.1 解耦为何很重要
过于复杂的代码往往在可读性、可维护性上都不友好。解耦保证代码松耦合、高内聚,是控制代码复杂度的有效手段。代码高内聚、松耦合,也就是意味着,代码结构清晰、分层模块化合理、依赖关系简单、模块或类之间的耦合小,那代码整体的质量就不会差。
7.2 代码是否需要解耦
间接的衡量标准有很多,比如,看修改代码是否牵一发而动全身。直接的衡量标准是把模块与模块、类与类之间的依赖关系画出来,根据依赖关系图的复杂性来判断是否需要解耦重构。
7.3 如何给代码解耦
给代码解耦的方法有:封装与抽象、中间层、模块化,以及一些其他的设计思想与原则,比如:单一职责原则、基于接口而非实现编程、依赖注入、多用组合少用继承、迪米特法则等。当然,还有一些设计模式,比如观察者模式。
发布评论