1:抽象与用户自定义类型
1.1用户自定类型(User-define type)
除了编程语言所提供的基本数据类型和对象数据类型,程序员可定义自己的数据类型
1.2数据抽象(Data Abstraction)
概念:由一组操作所刻画的数据类型,而非关注数据的具体表示。
例:
2:抽象类型和操作分类
2.1:类型的分类:
可变数据类型:提供了可改变其内部数据的值的操作(Date,StringBuilder对象等)
不可变数据类型:其操作不改变内部值,而是构造新的对象(String对象的concat方法等)
2.2:操作的分类:
构造器(creator):产生该类型的对象。可传入其它类型的参数来进行产生。(如果某构造器被设置为静态的,也成为工厂方法factory method)
生产器(producer):产生该类型的对象。必须至少传入一个该类型的对象,传入或不传入其它类型的参数。
观察器(observer):产生一个其它类型的数据。必须至少传入一个该类型的对象,传入或不传入其它类型的参数。
变值器(mutator):将传入该类型的对象的值进行改变。必须至少传入一个该类型的对象。(不可变类型和可变类型的区别在此,不可变类型没有变值器)
3:设计抽象数据型
①抽象类型应该由较简单的操作组成,这些操作可以组合拥有强大的功能,而不是由复杂而用处较少的操作组成。
②每个操作对应的是较为普遍的用法,而不是特殊情况,各个操作的应该处理相近类型的事情。比如一个运算类型,那么需要的操作就是加减乘除,而不要此时引入一个计算数组长度的操作。
③如果一个操作是常用的,那么就应该实现这个操作,哪怕它可以由其它操作交给用户来完成。比如求数组长度,用户可以根据知道数组索引来求得数组长度,但是由于求数组长度这个操作常用,我们就可以帮它实现,而不用交给用户再实现。
④类型可以是泛型如集合、数组、图等,也可以是特定类型如街道地图、电话簿等。但请不要将二者进行融合,不要在泛型里放入特定类型的操作,也不要在特定类型里放入泛型的操作。
4:表示独立性:(Representation Independence)
表示独立意味着外部代码不依赖于其调用的类的内部实现方式,即如果外部代码调用了这个类的方法,同时类的该方法发生改变,但只要该改变仍然符合规约,那么对于外部代码调用无影响。
作为一个实现者,只有当ADT的操作完全指定了先决条件和后决条件时,您才能安全地更改其表示形式,这样客户才知道依赖什么,并且您知道可以安全地更改什么。
5:不变性(Invarians)
不变性就是一个类内的所定义的属性(也就是之前提到的representation,如private int a = 1;)始终符合某种条件。
不变性是一个程序的特性,即无论在任何时候,这个特性都是成立的。例如不可变类型可以说是一个不变性,在遍历数组时,i<array.length恒成立是一个不变性。
不变性由ADT负责,与客户端无关。
保持ADT的不变性可以通过给类内部的属性设置为private类型避免外部代码调用修改和只允许通过类提供的方法来修改内部的属性等方式。
5.1:表示暴露:(rep exposure)
表示暴露即类内部的属性能够直接被外部访问到,如属性设置为public类型,或者返回值是一个类内部的可变类型的属性就会导致表示暴露。表示暴露会破坏表示独立,即当修改类内部实现代码时,可能会影响到外部使用到该内部属性的地方。
因此,在编写一个类时,应该仔细检查每个属性的类型(也不是说public不对,如果public的是不可变类型,那么也依旧不会导致错误,不会破坏表示独立)以及每个方法返回值的类型。
表示暴露对表示独立和保持不变性都有影响。
保持不变性和避免表示泄漏,是ADT最重要的一个Invariant!
6:表示不变性和抽象函数
6.1:A空间(abstraction space)和R空间(representation space)
A空间指的是从客户角度来看,是客户想要的值组成的空间。例如,客户想要的是一个大整数,那么所有的整数值组成的就是A空间。
R空间指的是由若干个对象(可能不止一个,通常是多个)组成的实现A空间的值的空间。如果A空间是所有整数值组成的,那么R空间可以是数值类型的数组,用来表示数字。
6.2:abstract function(抽象函数):
抽象函数:从R空间到A空间的映射。AF:R--->A.
通俗地讲,抽象函数代表的就是怎么用代码来实现客户的需求。
6.3:Rep invariant(表示不变性)
表示不变性:从R空间到布尔值的映射。RI:R--->T|F。如果一个R空间的值i存在到A空间的映射,那么RI(i)=T,否则为F。
通俗地讲,表示不变性代表的就是哪些代码(数据)可以用来实现客户的需求。
表示不变性RI:某个具体的“表示”是否是“合法的” 也可将RI看作:所有表示值的一个子集,包含了所有合法的表示值 也可将RI看作:一个条件,描述了什么是“合法”的表示值
6.4:检查不变性:
可以在构造器、变值器和产生器后对不变性进行检查(调用checkRep方法)