类的层次结构、属性与变量

在上一节结束时我们创建两个类:Thing 和 Treasure,尽管事实上这两个类共享了一些功能(特别是两者都包含 ‘name’),但它们是没有联系的。

现在,这两个类的重复看起来是不值一提的。但是,当你开始写一些复杂的程序时,你的类将会包含大量的变量和方法;你真的想将同样的事情一遍又一遍的重复吗。

对于其中一个类是其它(祖先)类的特殊类型结构来说创建一个类层次是更有意义的,这种情况下它会自动继承(inherit)祖先类的特征。例如,在我们简单的冒险游戏中,Treasure 是 Thing 的一个特殊的类型,因此 Treasure 就会继承 Thing 类的特征。

类层次——祖先(Ancestors)和后代(Descendants):在这本书中,我会经常提及“后代”类继承(inherit)自它们祖先类,这些术语意味着“相关”类之间的一种类似于家庭的关系。Ruby 中每一个类只有一个父亲,然而,它可能在一个很长很大的家庭树中,有许多代的父母、祖父母等等…

Thing 类的特征通常被定义在它内部,Treasure 类则会自动地“继承” Thing 类所有的的特性。所以,我们不需要再次对这些特征进行编码,而是额外添加一些 Treasures 类特有的特性。

通常地规则是,在创建类层次结构时,具有更多通用特征的类要比具有更多特殊特征的类层次更高一些。所以,只有一个 namedescription 的 Thing 类是具有 namedescription 以及 value 的 Treasure 类的祖先;Thing 类也可能是一些其它的特殊类的祖先,例如具有 namedescription 以及 exits 的 Room 类。

一个父亲,有多个孩子…
类的层次结构、属性与变量 - 图1
Thing 类具有 namedescription (在 Ruby 程序中,它们可能是内部变量 @name@description)。Treasure 和 Room 类都派生自 Thing 类,所以它们自动地继承了 namedescription 。Treasure 类添加了一个 value,所以它就具有 namedescriptionvalue ;Room 类添加了一个 exits,所以它就具有 namedescriptionexits
1adventure.rb

来让我们看看如何在 Ruby 中创建一个后代类。加载 1adventure.rb 程序,这只需要定义一个具有两个实例变量(instance variables)@name@description 的 Thing 类,它们的值可以在创建新的 Thing 对象时在 initialize 方法中赋值。

实例变量通常不能(也不应该)被外部直接访问,这是为了遵循上一章讲到的封装( encapsulation)原则。为了获得我们所需要的每个变量的值,我们需要一个 get 访问器方法,例如 get_name;为了给某个变量赋一个新值,我们也需要一个 set 访问器方法,例如 set_name