软件构造复习:第三章(下)

表示空间、抽象空间、AF

表示值构成的空间(R/表示空间):实现者看到和使用的值。
抽象值构成的空间(A/抽象空间):client看到和使用的值
在这里插入图片描述
Note.ADT开发者关注表示空间R,client关注抽象空间A。

抽象函数:R和A之间映射关系的函数,即如何将R中的每一个值解释为A中的每一个值。
AF:R→A

AF满足以下几个:
1.满射:A中每一个值都有一个或多个映射
2.未必单射:可能R多个值对应A的一个值
3.未必双射(一一映射)

R中的部分值并非合法的,在A中无映射值。

以注释的形式撰写AF、RI

不同的内部表示,需要设计不同的AF和RI

选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)–即如何映射到抽象空间中的值

同样的表示空间R,可以有不同的RI
即使是相同的R、同样的RI,也可以有不同的AF,即“解释不同”

设计ADT

  1. 选择R和A;
  2. RI–合法的表示值
  3. 如何解释合法的表示值–映射AF

做出具体的解释:每个rep value如何映射到abstract value。而且把这种选择和解释明确写到代码当中。

随时检查RI是否满足checkRep()

有益的可变性:对immutable的ADT来说,它在A空间的abstract value应是不变的,但其内部表示的R空间中的取值则可以是变化的。

在代码中用注释形式记录AF和RI:不能在Javadoc文档中写,防止被外部看到而破坏表示独立性/信息隐藏

  • 要精确的记录RI:rep中的所有fields何为有效
  • 要精确的记录AF:如何解释每一个R值
  • 表示泄露的声明:给出理由,证明代码并未对外泄露其内部表示

接口、抽象类、具体类

实现ADT
接口确定ADT的规约。接口之间可以继承与扩展;一个类可以实现多个接口;一个接口可以有多种实现类

Interface和Class:定义和实现ADT
也可以不需要接口直接使用类作为ADT,既有ADT定义也有ADT实现。(更偏向使用接口来定义变量)

接口优点:

  • Safe from bugs
  • Easy to understand
  • Ready for change

抽象方法:只有定义没有实现。
抽象类:具有抽象方法的类;抽象类不能实例化。(不能用new生成对象)
具体类:其中的所有方法都必须实现!!

继承、override

Strict Inheritance(严格继承):子类只能添加新的方法,无法重写超类中的方法。(final)

public class Car{
	public final void drive(){...}//不能在子类重写
}

重写/覆盖的函数:完全同样的signature。(形参,函数名,返回类型)
实际执行时调用哪个方法,运行时决定
ps:1.父类型中被重写函数体不能为空:意味着对其大多数子类型来说,该方法是可以被直接复用的;对某些子类型来说,有特殊性,故重写父类型的函数,实现自己的特殊要求
2.如果父类型中的某个函数实现体为空,意味着其所有子类型都需要这个功能,但各有差异,没有共性,在每个子类中均需要重写。
3.overriden methods是在run-time进行动态类型检查

Note.重写之后,利用super()复用父类型中函数的功能,并对其进行扩展。eg.super.message();重写的时候,不要改变原方法的本意

ps:继承某个抽象类的子类在实例化时,所有父类中的抽象方法必须已经实现

Note.

  • 如果某些操作时所有子类型都共有,但彼此有差别,可以在父类型中设计抽象方法,在各子类型中重写。
  • 所有子类型完全相同的操作,放在父类型中实现,子类型中无需重写。
  • 有些子类型有而其他子类型无的操作,不要在父类型中定义和实现,而应在特定子类型中实现。

多态、overload

多态(polymorphism)

  • 特殊(Ad hoc)多态:一个方法可以有多个同名的实现(方法/功能重载);
  • 参数化(Parametric)多态:一个类型名字可以代表多个类型(泛型编程);
  • 子类型多态、包含(Subtyping)多态:一个变量名字可以代表多个类的实例(子类型);

重载overload(特殊多态):多个方法具有同样的名字,但有不同的参数列表或返回值类型。
overload的价值:方便client调用,client可以用不同的参数列表,调用同样的函数。

Overloading is a static polymorphism(重载是静态多态):根据参数列表进行最佳匹配;静态类型检查;在编译阶段时决定要具体执行哪个方法。

overloading rules

  • 不同的参数列表
  • 相同/不同的返回值类型
  • 相同/不同的public/private/protected
  • 可以定义相同/不同的异常
  • 可以子啊同一个类内重载,也可以在子类中重载

参数多态性是指方法针对多种类型(具有通用的结构)时具有相同的行为,此时可使用统一的类型表达多种类型;在运行时根据具体指定类型确定(编译成class文件时,会用指定类型替换类型变量)

泛型

泛型编程是一种编程风格,其中数据类型和函数是根据待定的类型编写的,随后在需要时根据参数提供的特定类型进行实例化。

ps:类中如果声明了一个或多个泛型变量,则为泛型类;泛型接口(字面意思)

Note.通配符:只在使用泛型的时候出现,不能在定义中出现。
eg.List<?> list=new ArrayList();
List<? extedns Animal>
List<? super Animal>

子类型多态:不同类型的对象可以统一的处理而无需区分,从而隔离了“变化”

等价性equals()和==

基于抽象函数AF定义ADT的等价操作,如果AF映射到同样的结果,则等价

==:引用(地址)等价性;对基本数据类型,使用等号判定相等
equals():对象等价性;对对象类型,使用equals
ps:如果对象数据类型使用等号判断是否相等,是在判断两个身份对象身份表示ID是否相等(指向内存里的同一段空间)

Note.instanceof:进行类型比较和null值判定;判断某个对象是不是特定类型(或其子类型);动态类型检查

ps:严格来说,在没有AF的情况下直接在equals()中判断每个域的等价性,是不正确的

equals()的自反、传递、对称

用“是否为等价关系”检验重写的equals()是否正确

hashCode()

程序中多次调用同一个对象的hashCode方法,都要返回相同的值

等价的对象必须有相同的hashCode(两个equal的objects,一定要有同样的hashCode)

不可变对象的引用等价性、对象等价性

不可变类型必须重写equals()和hashCode()。

可变对象的观察等价性、行为等价性

注意:如果某个mutable对象包含Set集合类中,当其发生改变后,集合类的行为不确定。

对可变类型,实现行为等价即可(equals()should implement behavioral equality)。就是说,只有指向同样内存空间的objects,才是相等的。

对可变类型来说,无需重写equals()和hashCode(),直接继承Object的两个方法即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值