***一个抽象的数据类型是由它的操作定义的:(抽象数据类型的实现如下图:↓)
1.数据类型的分类:
分为:可变和不可变的数据类型
2.抽象数据类型的操作的分类
分为:构造器(Creators)、生产器(Producers)、观察器(Observers)、变值器(Mutators)
构造器(creator):create new objects of the type。可能实现为构造函数或静态函数(如:ArrayList()、String.valueOf(Object Obj))(工厂方法)
变值器(mutator):change objects。(变值器通常返回void)返回值若为void,则必然意味着它改变了对象的某些内部状态.(返回值也可以不是void,例如Set.add()返回值就是布尔类型)
观察器(observer):take objects of the abstract type and return objects of a different type。观察抽象数据类型内部的属性
生产器(producer):create new objects from old objects of the type。从老的对象类型中创造出新的对象
***例:
Integer.valueOf() ---Creator
BigInteger.mod() ---Producer
List.addAll() ---Mutator
String.toUpperCase() ---Producer
Set.contains() ---Observer
Collections.unmodifiableList() ---Producer
BufferedReader.readLine() ---Mutator
含义:client(客户端)使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端(除非ADT的操作指明了具体的前置条件和后置条件,否则不能改变ADT的内部表示)
问题七:不变量(Invariants)
***不变性是不变量的一种类型(Immutability as a type of Invariants)
**例:下面则段代码会造成什么影响
解:由于Data是mutable类型的变量所以d会指向与t.getTimestamp一样的位置,当你修改d时,无形中Tweet类型的 t也被修改,这样Tweet的不变性就被破坏,尽管我们已经声明了timestamp为final。用snapshot图表示如下:
*解决方式:防御性的复制(Defensive copying):
定义一个获取时间的新的方法,在方法中国,不是直接获取tweet类中的timestamp,而是新建一个对象将其tweet中的timesamp的值复制过去。代码如下:
***例:解释如下代码会发生什么
解:这段代码中由于Date是可变的数据类型,而在进入循环的时候仅仅创建过一个对象date,所以当进入循环时,每次修改date,并将其赋给一个新的对象Tweet加入list时,都会修改以前加入list的Tweet中的date,用snapshot图表示如下:
解决方式:在每次构造一个新的Tweet对象时,构造函数中的timstamp都新创建一个Data类型的对象来接收传送过来的date的timestamp的值,这样就不会在修改date时,同时修改掉以前的Tweet中的timestamp了,代码如下:
***综上:保持不变性和避免表示泄露,是ADT最重要的一个Invariant
R:表示值构成的空间,也称为表示空间。表示空间的值是实现实际对象的值
A:抽象值构成的空间,也成为抽象空间。抽象空间的值是客户端看到和使用的值
(ADT实现者关注表示空间R,用户关注抽象空间A)
AF:抽象函数,是R和A之间映射关系的函数(AF:R->A)
RI:表示不变性RI,某个具体的“表示”是否是“合法的”(RI:R->boolean)(也可以将RI看作所有表示值的一个子集,包含了所有合法的表示值)(也可将RI看作一个条件,描述了什么是“合法的”的表示值)
*例1:
*例2: