程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

阅读数:23 2019 年 10 月 1 日 16:48

程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

我们再来略为讨论一下可见性的问题。

所谓可见,是数据相对于计算(的需要)而言的——如果数据不需要参与计算,则讨论它的可见与不可见本身就失去了意义。我们这里所说的计算,在对象系统中被称为行为 / 方法(且方法本身也是对象的性质之一)。这些与计算相关的因素,综合起来有如下几种情况。

其一,以一个对象来说,属性若以“被计算数据(P)”和“计算行为(M)”来区分的话,则 P 本身就有对 M 的可见性问题,如图 24 所示。

图 24 对象的数据之于行为的可见性问题

程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

M1 是否可以访问 P1?若可以,那么 M2 能否访问 P1?这个问题的有趣之处在于,在当前我们对对象系统的设计中,Mx 是能访问 Px 的,因为它们是属于同一个对象的性质。但是,如果 P1 只需要被 M1 访问,那么 P1 是否应该仅是 M1 的一个私有变量?例如代码:

复制代码
aMan = {
height: 1.75, // 身高
heighten: function() { ... }, // 增高
weight: 70, // 体重
loseweight: function() { ... } // 减肥
};

显然,身高与体重都是aman的性质,但身高与增高有关,与减肥却没什么关系。所以是否应该考虑heightheighten()的一个私有的、计算用的数据呢?但如果这样,height难道又不是aman的性质了吗?

更进一步说,我们的现状是:让任一方法 M1 都必将面对所有的属性 Px。这在一定程度上增加了对象自身构造时的复杂性。

其二,以一个对象作为系统中待处理的数据来说,则对象本身(与其所有属性)就有对系统的可见问题,如图 25 所示。

图 25 对象之于系统的可见性问题

程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

因为外部系统可能需要了解 P22 与 M22,而并不需要了解 P11 与 M11,因此 P11 与 M11 就应当对外部不可见(内部私有,internal-private),P22 与 M22 就应该是对外部可见的(公开,public)。再者,与上面的一个问题相关,在 P22 与 M22 中又将涉及到 P22 是否需要被公开的问题。

其三,若一个对象作为继承层次中的一层,则对象有对其他末端层次的可见问题,如图 26 所示。

图 26 对象在继承层次上的可见性问题

程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

因为对象 C 的实现可能依赖于一些对象 B 的性质,也可能根本就不依赖某些性质。对于完全不依赖的,就不需要由 B 继承到 C,因此这里的“私有”并不单单表明对象 C 是否可见,而且表明性质 P11/M11 是否要从类继承关系上完全隔离开来,确保对象 C 无法通过继承得到。反之,我们就应该让对象 C 可以继承 P22/M22,以确保其他行为可以访问它们(内部——在继承链上的——保护,internal-protected)。

其四,基于上述问题的进一步设问是:若外部系统中有一个对象是继承自对象 B 而得来的呢?如图 27 所示。

图 27 跨系统继承(对象复用)时的可见性问题

程序原本(五十七):程序设计的核心思想——对象系统:表达、使用与模式(可见性同样也是多余的:它是对继承性的补充与展现)

这种情况下,对于 P22/M22,我们仍然需要让外部系统可以在对象 D 中访问到(外部——在继承链上的——保护,protected)。

回顾上一小节的的讨论:多态性是对象的性质在其继承关系上的表现,而本节内容则指出这一表现的具体方法(即可见性)包括:

  • 可见但限于在内部实现的子类的,即 internal-protected;
  • 可见并允许包括外部系统实现的所有子类的,即 protected。

上述分析也表明:如果要在对象继承中,利用子类相对于父类的多态特性,则相关的、在继承链上的性质必然是上述两种可见性的。除此之外,其他的可见性还包括:

  • 不可见,即 private;
  • 可见但与继承性无关,即 internal 和 public。

评论

发布