软件构造复习思考(第七八章)

一 抽象

抽象数据类型举例

int:不可变数据类型,没有mutator函数
List:可变数据类型,接口,有mutator函数
String:不可变数据类型,没有mutator函数
认识Java中的ADT概念
软件构造复习思考(第七八章)

设计抽象类

抽象类型的表示是独立与其表示(真是的数据结构和成员)
只有当我们通过前置条件和后置条件充分明确了ADT的操作,使调用者知道可以依赖哪些内容,实现者知道可以安全更改哪些内容,此时才可以修改内部表示。

ADT的不变性
好的ADT最重要属性是保持其不变性。
在程序运行过程中,程序始终保持不变的性质,不可变就是不可变类型的重要不变性。ADT自身有责任确保其不变性,而不是依赖于调用者或者其他模块 。
为什么需要不变性?
当ADT保持自己的不变性时,推理代码变得容易得多。
如果您可以指望字符串永远不会改变,那么在调试使用字符串的代码时,或者在尝试为另一个使用字符串的ADT建立不变量时,可以排除这种可能性。与之形成对比的是,字符串类型保证只有当其客户承诺不更改它时,它才是不可变的。然后您必须检查代码中可能使用字符串的所有位置。
要假设用户会有意或者无意地挑战不变性。

R:表示空间,实现时用到的值空间
A:抽象值空间,需要支持的值空间
表示不变性
RI : R → boolean
RI告诉我们空间R中的r是否被AF映射到了空间A中的某个值。
RI形成了空间R的一个子集(子集中的所有元素均被AF映射到了空间A中)
什么决定了AF和RI
AF和 RI 既不由选定的表示值空间决定,也不由抽象值空间单独决定,表示值空间确定后,AF和RI也不是确定的。
比如,我们有同样的R空间,单射可能会有不同的表示不变性。

RI和AF如何影响ADT设计
ADT设计的关键:不仅是选择两个空间(面向规格说明的抽象值空间和面向实现的表示值空间), 而且要决定表示值(RI)和如何映射(AF)。

二 面向对象

对象
识别现实世界中事物的状态和行为,是开始OOP的好方法。观察对象有哪些状态,有哪些行为。

每个对象都有一个类,类定义了类型和实现, API 类的方法就是其应用程序接口

接口的优势
调用者理解ADT时只需要理解接口即可
调用者不能在 ADT的表示上创建无意的依赖
不同实现可以在不同的类中
抽象数据类型的多个不同表示可以共存于同一个程序中,作为实现接口的不同类

接口小结
有助于编译器帮助检查ADT实现中的bug,也有助于用户脱离代码理解方法,可以根据需求选择合适的实现,实现性能的折中。ADT的规格说明中,对方法的实现未明确指定,为实现提供了*,可以有多种方式实现。一个类可以实现多个接口,展现多个视图,是对Java不支持多继承的一种补偿。通过对多个实现在性能和bug free方面的比较,进行实现的选择。

(1)覆盖/重写

子类可以重新实现父类中的方法 ,但要有相同的签名。根据调用时的对象类型决定被调用方法的版本,也就是new的时候左侧定义的类型是什么。
严格重写
默认父类中的方法均是可以被重写的,而“严格继承”则只能继承不能重写,这样的方法需要被定义为final。
可重写方法设置为空
例如,某个方法在各个子类中通用性很强,则可以编写具体的方法体,如果各自实现不同或者常常被重写,不如设置方法体为空。而如果想放弃父类的方法,可以通过空方法体来重写父类的方法。

(1)三种多态性的类型

多态性是指为不同类型的实体提供一个接口,或者使用一个符号来表示多个不同的类型。
Ad hoc polymorphism:一个函数可以有多个同名的实现(方法重载)
参数多态性:一个类型名字可以代表多个类型(范型编程)
子类型:一个变量名字可以代表多个类的实例( 子类型)

(2)Ad hoc polymorphism和重载

Ad hoc polymorphism:一个函数作用于几个不同的类型(可能不显示一个共同的结构)并且可能以不同的方式对每个类型进行操作。
重载:重载是指在一个类中存在多个同名函数,必须具有不同的参数列表,返回值类型可同可不同。重载为调用者带来了方便(便于记忆同类方法的名字) 。重载是一种静态的多态,通过参数列表决定依赖哪个实现,在编译时决定调用哪个方法。
重载规则
必须改变参数列表
可以改变返回值类型
可以改变访问修饰符
可以进行新的或更广泛的异常检查
对某个方法的重载可以在一个类中进行,也可以在子类中进行。此时需要注意同重写的区别:如果父类和子类中两个方法的签名相同,则为重写;名称一样,参数列表不一样时,则为重载。

重写与重载
重写使用原签名,而重载与原签名不同。但使用时两者并不冲突, 子类重载了父类的方法后,子类仍然继承了被重载的方法。
软件构造复习思考(第七八章)

上一篇:关于Java ADT的学习总结


下一篇:软件构造复习第六章