对象和数据结构
是什么
首先明确两类数据的抽象方式——对象和数据结构。
- 所谓对象,是标准的面向对象的产物,可以基于多态(继承父类或实现抽象类或接口),它的成员变量多为私有,向外提供一组共有的方法来暴露操作接口(包括但不限于getter和setter)。例如,在“为几何图形求面积”的场景中,我们可以给出基于对象设计的如下解决方案——对于接口Shape,有多个实现类Circle、Square、Triangle等,每个实现了都实现了接口的area方法,并且有不同的具体实现细节。
- 所谓数据结构,是一种偏向于面向过程思想的产物。它本身只是数据的一种聚合和载体,而不涉及到业务逻辑和计算过程,因此无所谓是否会暴露内部的细节。所以,它可能提供一组共有的成员变量,也可能提供一些直接进行数据获取和操作的公有方法,但是一定不会提供任何涉及到复杂的逻辑处理的方法。例如,同样是在“为几何图形求面积”的场景中,基于数据结构设计,我们可以给出如下的解决方案——设计Circle、Square、Triangle等数据结构类,每个类只提供共有的、表示几何特征的成员变量,再设计一个操作类Geometry,该类的area以object为入参,通过判断入参的类型,来进行不同的求取面积的操作。
两种抽象方式的比较
对象和数据结构是两种互相对立的设计思想,其主要区别如下:
- 它们一个偏向面向对象而另一个偏向面向过程;
- 对象设计强调对外部隐藏其内部的细节,数据结构设计则没有这一约定;
- 基于数据结构的面向过程式的代码,便于在不改动既有数据结构的前提下添加新的函数(只需要对操作类做变更);基于对象的面向对象式的代码,便于在不改动既有函数的前提下添加新的类型。
另外,还引出两点思考:
- 不要无脑给任何类都做“变量私有、方法共有”的设计,要有意识的区分“对象”和“数据结构”。
- 要么是对象,要么是数据结构,不能暧昧不清。
一个类,如果所有的变量都私有,但是提供了全面的getter和setter,那么这个类的实现细节其实也是通过这些getter和setter暴露了出来,因此它应该算作“数据结构”而非“对象”。
Demeter定律
Demeter定律认为,模块不应该了解它所操作的对象的内部细节。
对于一个类C中的方法f,它只能调用以下几类来源的方法:类C内的其他方法;
- f中直接创建的对象的方法;
- 作为参数传递给f的对象的方法;
- C的成员变量所持有的对象。
f不可以调用某些方法的返回值所持有的方法。例如下面展示的代码就是违反Demeter定律的(即链式调用)。
A a = b.getC().getA();
解决链式调用的方法: