本章的内容很有启发性。

对象和数据结构

是什么

首先明确两类数据的抽象方式——对象和数据结构。

  • 所谓对象,是标准的面向对象的产物,可以基于多态(继承父类或实现抽象类或接口),它的成员变量多为私有,向外提供一组共有的方法来暴露操作接口(包括但不限于getter和setter)。例如,在“为几何图形求面积”的场景中,我们可以给出基于对象设计的如下解决方案——对于接口Shape,有多个实现类Circle、Square、Triangle等,每个实现了都实现了接口的area方法,并且有不同的具体实现细节。

image.png

  • 所谓数据结构,是一种偏向于面向过程思想的产物。它本身只是数据的一种聚合和载体,而不涉及到业务逻辑和计算过程,因此无所谓是否会暴露内部的细节。所以,它可能提供一组共有的成员变量,也可能提供一些直接进行数据获取和操作的公有方法,但是一定不会提供任何涉及到复杂的逻辑处理的方法。例如,同样是在“为几何图形求面积”的场景中,基于数据结构设计,我们可以给出如下的解决方案——设计Circle、Square、Triangle等数据结构类,每个类只提供共有的、表示几何特征的成员变量,再设计一个操作类Geometry,该类的area以object为入参,通过判断入参的类型,来进行不同的求取面积的操作。

image.png

两种抽象方式的比较

对象和数据结构是两种互相对立的设计思想,其主要区别如下:

  • 它们一个偏向面向对象而另一个偏向面向过程;
  • 对象设计强调对外部隐藏其内部的细节,数据结构设计则没有这一约定;
  • 基于数据结构的面向过程式的代码,便于在不改动既有数据结构的前提下添加新的函数(只需要对操作类做变更);基于对象的面向对象式的代码,便于在不改动既有函数的前提下添加新的类型。

另外,还引出两点思考:

  • 不要无脑给任何类都做“变量私有、方法共有”的设计,要有意识的区分“对象”和“数据结构”。
  • 要么是对象,要么是数据结构,不能暧昧不清。
  • 一个类,如果所有的变量都私有,但是提供了全面的getter和setter,那么这个类的实现细节其实也是通过这些getter和setter暴露了出来,因此它应该算作“数据结构”而非“对象”。

    Demeter定律

    Demeter定律认为,模块不应该了解它所操作的对象的内部细节。
    对于一个类C中的方法f,它只能调用以下几类来源的方法:

  • 类C内的其他方法;

  • f中直接创建的对象的方法;
  • 作为参数传递给f的对象的方法;
  • C的成员变量所持有的对象。

f不可以调用某些方法的返回值所持有的方法。例如下面展示的代码就是违反Demeter定律的(即链式调用)。

  1. A a = b.getC().getA();

解决链式调用的方法:

  • 为每一个方法的返回值都创建一个对应的变量来承接;
  • 如上文所示的代码段,对b提供的方法做进一步的抽象和聚合,变为:
    1. A a = b.createA();

    总结

    本章中,其实还是没有哦很清楚的阐明“数据结构”和“对象”的清晰界限是什么。不过我认为这个不重要,中哟的是掌握这两种数据抽象的方法,并明确在什么场景下用什么方法进行数据抽象。