对象导论笔记-第二天 继承

08/18/2011

1.6 继承

对象这种观念,本身就是十分方便的工具,使得你可以通过概念将数据和功能封装到一起,因此可以对问题空间的观念给出恰当的表示,而不用受制于必须使用底层机器语言。

遗憾的是,这样做还是有很多麻烦:在创建了一个类之后,即使另一个新类与其具有相似的功能能,你还是得重新创建一个新类。如果我们能够以现有的类为基础,复制它,然后通过添加和修改这个副本来创建新类那就好多了。通过继承便可以达到这样的效果,不过也有例外,当“源类”(基类,超类,父类)发生变动时,被修改的“副本”(导出类,继承类,子类)也会反应出这些变动。

继承使用基类型和导出类型的概念表示了类型之间的相似性。一个基类型包含其所有导出类型所共享的特性和行为。可以创建一个基类型来表示系统中某些对象的核心概念,从基类型众导出其他类型,来表示此核心可以被实现的各种不同方式。

对使用面向对象设计的人们来说,困难之一是对于通过使用对象,类型层次结构作为主要模型。从开始到结束过于简单了。对于训练有素,善于寻找复杂的解决方案的头脑来说,可能会在一开始被这种简单性给难倒。

当继承现有类型时,也就创造了新的类型。这个新的类型不仅包括现有类型的所有成员,而且更重要的是它复制了基类的借口。通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。

由于基类和导出类具有相同的基础接口,所以伴随此接口的必定有某些具体实现。有两种方法可以使基类与导出类产生差异。

  1. 第一种方法非常直接:直接在导出类中添加新方法。
  2. 第而种也是更重要的一种使导出类和基类之间产生差异的方法是改变现有基类的方法和行为,这被称为覆盖(overriding)基类方法。

1.6.1 “是一个(is a)”与“像一个(is like a)”关系

对于继承可能会引发某种争论:继承应该只覆盖基类的方法。在某种意义上,这是一种处理继承的理想方式。我们称之为(is a)关系。这可以被视为替代原则

有时候必须在导出类型最终添加新的接口元素,这样也就扩展了接口。这个新的类型仍然可以替代基类,但是这种替代并不完美,因为基类无法访问新添加的方法。我们称之为(is like a)关系。尽管新对象的接口已经被扩展了,但是现有系统除了原来借口之外对其他东西一无所知。

当你看到替代原则时,很容易认为这种方式(纯粹替代)是唯一可行的方式,而且事实上,用这种方式设计是很好的。但是你会时常发现,同样显然的是你必须在导出类的借口中添加新方法。只要仔细审视,良种方法的使用场合应该是相当明显的。

举例:当我们设计一个数据库的时候,可以设计一个 C/S 端管理数据。同时我们需要一个 B/S 端来支持更加简单的远端操作!这样 B/S 模式完全可以使用 C/S 端的基类,我们只需要扩展它就可以完成工作(比如:添加 JSON 数据处理方法)。整体结构也会比较清晰!