面向可维护的构造技术
software maintenance and evolution
软件维护:修复错误,改善性能
运维:处理来自用户报告中的故障、问题(bug issue localization,testing,fix,and documenting changes)
修改代码后:测试所做的修改,回归测试,记录变化,除了修复问题,不能引入新的故障,最大的问题是修改后没有足够的文档记录和测试
软件演化:对软件进行持续的更新
软件的大部分成本来自维护阶段
雷曼的软件进化定律:在最初的设计中充分考虑未来的变化,避免因为频繁变化导致软件复杂度的增加和质量的下降
可维护的设计结构:
-
模块化
-
OO设计原则
-
OO是寂寞是
-
基于状态的构造技术
-
表驱动的构造技术
-
基于语法的构造技术
metrics of maintainability
维护的指标
可维护性,可拓展性,灵活性,可适应性,可管理性,支持性
圈复杂度(不同的代码路径)
代码行数
霍尔斯特德容积:一种基于源代码中(不同的)运算符和操作数数目的复合度量
可维护性指数MI:霍尔斯特德容积HV,圈复杂度CC,每个模块平均行数LOC,每个模块注释行百分比COM
继承的层次数,类之间的耦合度,单元测试的覆盖度
模块设计和设计原则
模块化编程:高内聚,低耦合,分离关注点,信息隐藏
评价模块性的五个指标
可分解性
可组合性
可理解性
可持续性(发生变化是受影响范围最小)
出现异常之后的保护(出现异常后受影响的范围最小)
模块化设计的五个规律
直接映射
尽可能少的接口
尽可能小的接口
显示接口
信息隐藏
松耦合和高内聚
耦合是模块之间依赖性的度量。如果一个模块中的更改可能需要另一个模块中的更改,则两个模块之间存在依赖关系。
模块之间的耦合程度由以下因素决定:
-
模块之间的接口数量(数量)
-
每个接口的复杂性(质量)
内聚性是衡量模块的功能或职责有多紧密相关的一个指标。 如果模块的所有元素都朝着同一个目标工作,那么模块就具有很高的内聚性。
最好的设计是有着低耦合和高内聚
耦合度和内聚度负相关
OO Design principles SOLID
SOLID: 5 个类设计原则
-
SRP:单一责任原则
-
OCP:开放-封闭原则
-
LSP:Liskov替换原则
-
ISP:依赖转置原则
-
DIP:接口聚合原则
单一责任原则SRP(single responsibility principle)
不应该多于一个原因让ADT发生变化,否则就拆分开
责任:变化的原因
一个类一个责任
否则会引起不良后果:
-
引入额外的包,占据资源
-
导致频繁的重新配置,部署等
开放封闭原则OCP(open/close principle)
拓展性的开放(模块的行为是可拓展的,而该模块可表现出新的行为已满足需求的变化)
修改的封闭(模块自身的代码不应该被修改,拓展模块行为的一般途径是修改模块的内部实现,如果一个模块不能被修改,是有固定的行为)
解决方案:抽象技术,使用继承和委托,组合
里氏替换原则LSP
子类型必须能够替换基类
派生类必须能够通过基类的接口使用,客户端无需了解两者之间的差异
接口隔离原则ISP (interface segregation principle)
不能强迫客户端依赖于他们不需要的接口,只提供必须得接口
依赖转置原则DIP(Dependency Inversion Principle)
抽象的模块不应该依赖于具体的模块,具体的应该依赖于抽象
换句话说,delegation的时候,通过interface建立联系,而不是具体子类
语法驱动的构造
有一类应用,从外部读取文本数据,在应用中进一步处理
输入文件有特定格式,程序需要读取文件,并从中抽取正确的内容
从网络上传输过来的消息,遵循特定的协议
用户在命令行输入的指令,遵循特定的格式
内存中存储的格式串,也要有格式需要
使用grammar判断字符串是否合法,并解析乘程序里使用的数据结构
通常是递归的数据结构
正则表达式
语法成分
用语法定义一个字符串
终止节点,叶节点:无法再往下拓展,通常表示为字符串
产生式节点,非终止节点:遵循特定规则,利用操作符,终止节点和其他非终止节点,构造新的字符串
operators in a grammar
连接,重复*,选择|
*,?,+最高优先级,|最低优先级
::= 产生
基本语法之外的操作符: ?(optional) +(1+重复)[...]一个字符全属于[]中的一元字符串[a-zA-Z]
[^...]字符全不属于这个[]的一元字符串
语法中的递归
解析树
Markdown 和 HTML
正则语法和正则表达式
正则语法:简化后可以表达为一个产生式不包含任何非终止节点。
正则表达式:去除引号和空格,从而使表达更简洁
-
. 一个单独的char
-
\d 一个数字[0-9]
-
\s 一个空白符 \t \n 空格
-
\w 一个word character [a-zA-Z0-9]
问号?可以表示重复前面内容的0次或一次,也就是要么不出现,要么出现一次。
上下文无关语法
大多数编程语言是上下文无关的
parsers
输入文本,与特定的语法规则建立匹配,输出结果
parser: 将文本转化为 parse tree
AST
在java中使用正则表达式
Pattern是对regex正则表达式进行编译后得到的结果
Matcher:利用Pattern对输入的字符串进行解析