第十章 面向可维护性的构造技术
第十章 面向可维护性的构造技术
软件维护与演进
-
软件维护:修复错误、改善性能
-
运维是软件开发中最困难的工作之一
-
处理来自用户报告的故障 / 问题
-
需要代码后
- 测试所做的修改
- 回归测试
- 记录变化
-
-
软件演化:对软件进行持续的更新
-
软件的大部分成本来自于维护阶段
面向可维护性的构建
- 模块化
- OO 设计原则
- OO 设计模式
- 基于状态的构造技术
- 表驱动的构造技术
- 基于语法的构造技术
可维护性指标
可维护性的许多名称
- Maintainability 可维护性
- Extensibility 可扩展性
- Flexibility 灵活性
- Adaptability 可适应性
- Manageability 可管理性
- Supportability 支持性
一些常用的可维护性指标
-
Depth of Inheritance 继承的层次数
- 层越多越难维护
-
Class Coupling 类之间的耦合度
- 好的软件设计要求类型和方法应该具有高内聚和低耦合
- 高耦合表示设计难以重用和维护,因为它与其他类型有许多相互依赖性
-
Unit test coverage 单元测试的覆盖度
-
Cyclomatic Complexity 圈复杂度
- 圈太复杂不容易被测试
-
Lines of Code 代码行数
- 行数长的应该被拆分
-
Maintainability Index (MI) 可维护性指数
- 计算一个介于 0 和 100 之间的索引值,该值表示维护代码的相对容易程度。
模块化设计和模块化原则
评估模块化的五个标准
-
Decomposability (可分解性)
-
Composability (可组合性)
-
Understandability (可理解性)
-
Continuity (可持续性)
- 发生变化时受影响范围最小
-
Protection (出现异常之后的保护)
- 出现异常后受影响范围最小
模块化设计的五个规则
- Direct Mapping (直接映射)
- Few Interfaces (尽可能少的接口)
- Small Interfaces (尽可能小的接口)
- Explicit Interfaces (显式接口)
- Information Hiding (信息隐藏)
耦合
-
耦合性是衡量模块之间的依赖性
-
耦合程度决定因素
- 模块之间接口的数量
- 每个接口的复杂性
内聚
-
内聚是衡量一个模块的功能或责任有多强的关联
- 如果一个模块的所有元素都在为同一个目标工作,那么这个模块就有很好的内聚
OO Design Principles: SOLID
SOLID:5类设计原则
-
(SRP) The Single Responsibility Principle 单一责任原则
- 不应有多于1个的原因使得一个类发生变化,否则就拆分开
- 一个类,一个责任
-
(OCP) The Open-Closed Principle (面向变化的)开放-封闭原则
-
对扩展性的开放
- 模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化
-
对修改的封闭
- 模块自身的代码是不应被修改的
- 扩展模块行为的一般途径是修改模块的内部实现(修改继承或者委派的类)
- 如果一个模块不能被修改,那么它通常被认为是具有固定的行为
-
关键的解决方案:抽象技术
- 使用继承、组合/委派
-
-
-
(LSP) The Liskov Substitution Principle Liskov替换原则
- 子类型必须能够替换其基类型
- 派生类必须能够通过其基类的接口使用,客户端无需了解二者之间的差异
-
(ISP) The Interface Segregation Principle 接口隔离原则
-
不能强迫客户端依赖于它们不需要的接口:只提供必需的接口
-
不要强迫类来实现他们不能实现的方法
-
避免“胖”接口
- 不够聚合
- 胖接口可分解为多个小的接口
- 不同的接口向不同的客户端提供服务
- 客户端只访问自己所需要的接口
-
-
-
-
(DIP) The Dependency Inversion Principle 依赖转置原则
-
高级别的模块不应该依赖于低级别的模块。两者都应该依赖抽象。
-
-
-
语法驱动的构造
-
有一类应用,从外部读取文本数据,在应用中做进一步处理
- 输入文件有特定格式,程序需读取文件并从中抽取正确的内容
- 从网络上传输过来的消息,遵循特定的协议
- 用户在命令行输入的指令,遵循特定的格式
- 内存中存储的字符串,也有格式需要
-
使用grammar判断字符串是否合法,并解析成程序里使用的数据结构
- 从语法产生的数据结构通常是递归数据类型
- 根据语法,开发一个它的解析器,用于后续的解析
语法的组成部分
-
终止节点、叶节点
- 文本串无法再往下扩展
- 通常表示为字符串
-
产生式节点,非终止节点
-
操作符
-
Concatenation 连接
- x ::= y z x matches y followed by z
-
Repetition 重复
- x ::= y* x matches zero or more y
-
Union 选择
- x ::= y | z x matches either y or z
-
[…]
- x ::= [a-c] is equivalent to x ::= ‘a’ | ‘b’ | ‘c’
- x ::= [aeiou] is equivalent to x ::= ‘a’ | ‘e’ | ‘i’ | ‘o’ | ‘u’
-
[^…]
- x ::= [^a-c] is equivalent to x ::= ‘d’ | ‘e’ | ‘f’ | …(all other characters)
-
优先级
- 后缀运算符 *、?(重复0或1次) 和 +(1次及以上) 具有最高的优先级
- 其次是连接
- 最后是选择
- 括号可以改变优先级
-
正则语言和正则表达式
-
正则语法:简化之后可以表达为一个产生式而不包含任何非终止节点
-
符号
- . any single character
- \d any digit, same as [0-9]
- \s any whitespace character, including space, tab, newline
- \w any word character, including underscore, same as
- [a-zA-Z_0-9]
- ., (, ), *, +, … escapes an operator or special character so that it matches literally