第六章第一节 可维护性的度量与构造原则
可维护性的常见度量指标
- 可维护性
- 除此之外,可维护性还有其他许多别名:可扩展性(Extensibility)、灵活性(Flexibility)、可适应性(Adaptability)、可管理性(Manageability)、支持性(Supportability)。总之,有好的可维护性就意味着容易改变,容易扩展。
- 软件可维护性的五个子特性:
- 易分析性。软件产品诊断软件中的缺陷或失效原因或识别待修改部分的能力。
- 易改变性。软件产品使指定的修改可以被实现的能力,实现包括编码、设计和文档的更改。如果软件由最终用户修改,那么易改变性可能会影响易操作性。
- 稳定性。软件产品避免由于软件修改而造成意外结果的能力。
- 易测试性。软件产品使已修改软件能被确认的能力。
- 维护性的依从性。软件产品遵循与维护性相关的标准或约定的能力。
- 一些常用的可维护性度量标准:
- 圈复杂度(CyclomaticComplexity):度量代码的结构复杂度。
- 代码行数(Lines of Code):指示代码中的大致行数。
- Halstead Volume:基于源代码中(不同)运算符和操作数的数量的合成度量。
- 可维护性指数(MI):计算介于0和100之间的索引值,表示维护代码的相对容易性。 高价值意味着更好的可维护性。
- 继承的层次数:表示扩展到类层次结构的根的类定义的数量。 等级越深,就越难理解特定方法和字段在何处被定义或重新定义。
- 类之间的耦合度:通过参数,局部变量,返回类型,方法调用,泛型或模板实例化,基类,接口实现,在外部类型上定义的字段和属性修饰来测量耦合到唯一类。
- 单元测试覆盖率:指示代码库的哪些部分被自动化单元测试覆盖。
Maintainability Index (MI) 可维护性指数
内聚性
- 又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。
- 所谓高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则。
耦合性
- 也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。
- 对于低耦合,粗浅的理解是:一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。模块与模块之间的接口,尽量的少而简单。如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。这样有利于修改和组合。
最好的原则:
模块内高内聚,模块间低耦合
SOLID
(SRP) The Single Responsibility Principle 单一责任原则
(OCP) The Open-Closed Principle 开放——封闭原则
(LSP) The Liskov Substitution Principle Liskov 替换原则
(ISP) The Interface Segregation Principle 接口聚合原则
(DIP) The Dependency Inversion Principle 依赖转置原则
1.SRP
需要修改某个类的时候原因有且只有一个。换句话说就是让一个类只做一种类型责任,当这个类需要承当其他类型的责任的时候,就需要分解这个类。
反例:
正例:
2.OCP
对扩展性的开放:
模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化
对修改的封闭:
但模块自身的代码是不应被修改的
扩展模块行为的一般途径是修改模块的内部实现
如果一个模块不能被修改,那么它通常被认为是具有固定的行为
正确示例:
3.LSP
LSP: 子类型必须能够替换其基类型
派生类必须
能够通过其基类的接口使用,客户端无需了解二者之间的差异
4.ISP
含义:客户端不应依赖于它们不需要的方法。换句话说,使用多个专门的接口比使用单一的总接口总要好。
客户模块不应该依赖大的接口,应该裁减为小的接口给客户模块使用,以减少依赖性。如Java中一个类实现多个接口,不同的接口给不用的客户模块使用,而不是提供给客户模块一个大的接口
上图是一个反例:
用户并不一样需要eat操作,因此最好把eat和work分开。
5.DIP
高层模块不应该依赖于低层模块,二者都应该依赖于抽象
抽象不应该依赖于具体,具体应该依赖于抽象
简单的说,在copy中使用的是接口,把原先依赖于具体的reader和writer改成抽象的接口。