软件构造5 6 7章重点整理
第五章 设计规约
1 编程语言中的函数和方法
注意:在调用方法时,参数类型不匹配-静态检查
返回值类型是否匹配,也是静态类型检查阶段完成
“方法”是程序的积木,可以被独立开发、测试、复用
使用“方法的客户端”,无需了解方法内部具体如何工作的——“抽象”
2 规范:通信用编程
(1)编程中的记录
Java API documentation:an example
类层次结构
直接子类
类的描述
函数构造摘要
方法总结
每种方法和构造函数的详细描述:method signature、description、parameters、returns
记录假设
变量的数据类型定义
Java实际上在编译时检查这个假设,并保证程序中没有违反这个假设的地方
Final关键字定义了设计决策“不可改变”
(2)规范和合同(采用一种方法)
契约:程序与客户端之间达成一致
(3)行为等效
- 单纯的看实现代码,并不足以判断不同的implmentation是否是“行为等价的”
- 需要根据代码的spec(开发者与client之间形成的contract)判定行为等价性
- 在编写代码之前,需要弄清楚spec如何协商形成、如何撰写
(4)规格结构:预条件和后条件
前置条件:对客户端的约束,使用方法时必须满足的条件
后置条件:对开发者的约束,方法结束时必须满足的条件
前置条件满足,则后置条件满足
一个规范可以谈论什么?
只讨论方法的参数值和返回值,不讨论方法的局部变量和私有域
可变数据导致程序修改变得异常困难
归约的强度s2>=s1
前置条件更弱,后置条件更强
Spec变强:更放松的前置条件+更严格的后置条件
确定性
- 只能有一个返回值和一个最终状态
- 不存在有多个有效输出的有效输入
不确定性
同一个输入可以有多个输出
操作式规约:伪代码
声明式规约:没有内部实现的描述,只有“初-终”状态
声明式规约更有价值
第六章 ADT是由操作实现的
抽象值构成的空间:用户看到和使用的值
这些柏拉图式的实体并不存在,但他们是我们想要查看抽象类型元素的方式
抽象函数:R和A之间映射关系的函数,即如何去解
释R中的每一个值为A中的每一个值。
RI:另一个ADT不变量
一个将代表值映射到布尔值的代表不变量
AF:抽象函数
对不可变的ADT来说,他在A空间的abstract value是不可变的
但其对应的R空间的取值则是可以变化的
为什么需要有益突变
实现者自由通产允许性能改变
通过cache暂存某些频繁计算的结果
对tree数据结构进行插入或删除节点之后
在toString()的时候才进行约分计算
ADT不变量替换了先决条件
更安全的避免了bug
更容易理解
更容易改变
第七章 面向对象编程
接口和类:定义和实现ADT
接口之间可以继承与扩展
一个类可以实现多个接口
一个接口可以有多种实现类
使用接口+类的ADT:MyString
信息隐藏的好处
分解组成一个系统的类
加快系统开发
减轻维护负担
启用有效的性能调整
增加软件重用
使用接口隐藏的信息
使用接口类型声明变量
客户端仅使用接口中定义的方法
客户端代码无法直接访问属性
客户端可以直接访问非接口成员
特殊多态
一个方法可以有好几个同名的实现方式,在很多编程语言中,特殊多态被一种叫方法重载的形式支持。
参数化多态
代码的参数不被限制于特定的数据类型而进行的编程,也就是说一个类型名字可以代表多个类型。参数化多态更为熟知的叫法叫泛型编程。
子类型多态
一个变量的名字可以代表多个类的实例
重载是一种静态多态
根据参数列表进行最佳匹配
静态类型检查
在编译阶段时决定要具体执行哪个方法
重写是一种动态检查
重载在编译时发生(静态),重写在运行时发生(动态)
使用instanceof
是一种动态类型检查,而非静态类型检查
子类可以扩展父类的功能,但不能改变父类原有的功能