刚刚开始学习ADT,记录一下自己的学习收获,也欢迎大家共同交流。
一、ADT是什么?
除了编程语言提供的基本数据类型和基本对象类型之外,程序员自己定义的数据类型。ADT由操作定义,和内部如何实现无关。就比如说我想定义一个集合,这是一个抽象的数据类型,我可以用字符串数组,用整数数组等多种方法实现它,但无论我如何实现,它的功能不变。
二、设计一个ADT
1.设计原则
1.设计简洁,有一致的操作。比如说我们最好不要给一个list的ADT添加sum求和方法,如果元素类型是int那倒还好说,但如果是String这种无法求和的类型,就会产生一些麻烦的错误。
2.要足以支持客户对数据所有的操作需要,并且用操作满足客户需要的难度低。举例来说,一个list类型的ADT有get方法来获取内部的数据,有size方法来获取元素的个数,这就省去了客户自己遍历或者查找的操作。
2.表示独立性
客户使用ADT的时候无需考虑其内部是如何实现的,ADT内部的变化不影响外部spec和客户端。一个类如果要是ADT它就需要满足表示独立性,也就是消除暴露。
ADT不希望客户可以访问或者修改自己内部的数据,所以在设计ADT的时候要避免暴露。
1.当返回ADT属性的时候,返回immutable类型的数据,如果要返回mutable类型的数据就返回其副本。
2.类的成员最好都用private修饰,因为ADT的成员不希望被外部访问。
下面来看一个例子:
/**
*这个类代表一个家庭,家庭成员用public的List数组来存储
*有一个getMembers()方法直接返回people数组
*/
class Family{
public List<Person> people;
public List<Person> getMember{
return people;
}
...
}
现在假设我需要用到这个数组的成员,那么我会有如下操作:
void client1(Family f){
Person baby = f.people.get(f.people.size()-1);...
}
现在我要将这个家庭成员列表中的一个成员赋给新的对象baby,这里我直接用了people.get()和people.size()方法,这里我没有用类提供的方法来访问类的属性,而是直接用了List提供的方法,这就造成了暴露,也使得这个类的数据不再安全。
这是问题之一,还有一个问题就是其中的getNumbers()方法,直接返回了一个mutable类,如果我对返回的数组进行改变的操作,那这个类中的数组也会随之改变,这同样造成了暴露。所以一种更好的设计方案是:
class Family{
Set<Person> people;
List<Person> getMembers(){
return new ArrayList<>(people);
}
}
改成这样设计的话,首先Set类型中没有get方法,所以就无法直接通过属性来访问其中的元素了。
其次getMembers()方法的返回值是一个people的副本,这样用户对其进行任何操作都不会影响类中的属性了。
总结
先暂时写这么多,之后再补充关于RI和AF的内容,我也是处于初学阶段,希望能和你一起进步。