在面向对象设计的情况下提到“层次结构”,许多人就会想到“继承”。继承是逻辑层次结构的一种形式——分层是另一种形式。到目前为止,在面向对象设计中更常见的逻辑层次结构形式产生于分层。
如果一个类在其实现中实质地使用了一个类型,则该类在该类型上分层。
分层是把更小、更简单、更原始的类型建成更大、更复杂、更精密的类型的过程。通常,分层通过组合(例如HasA或HoldsA)发生,但是实质性使用的任何形式(即引起物理依赖的任何使用)都被认为是分层。
对客户端程序来说,分层类型的实例通常不是通过更高层对象的接口以编程方式访问的。隐含意思是,基本类型是抽象的一个较低层次。例如,一个人(Person)有一颗心(Heart)、一个大脑(Brain)、一个肝脏(Liver)等,然而这些分层的器官对象不是大多数健康人的公共接口的一部分。像一个表这样简单的对象经常作为链表的一个集合来实现,但是Link类本身不会用在写得很好的List类的接口中。
继承,连同动态绑定,可以用来区别面向对象语言(如C++)和基于对象的语言(如Ada),后者支持用户自定义类型和分层,但是不支持继承。继承的语义与分层有很大的不同。例如,基类和派生类的公共功能都可以通过客户端访问。对继承来说,越是特殊、具体的类越是依赖一般、抽象的类。对分层来说,在较高抽象层次上的类依赖较低抽象层次上的类。
在面向对象设计者的“兵工厂”中,分层是一种重要却常常配置不足的武器。新手在需要分层的地方尝试使用继承的情况并不少见。图1-23显示了逻辑层次结构的两个例子。在这两个案例中,Person为完成工作都隐含依赖Heart、Brain和Liver。在这里分层显然是正确的方法,因为一个Person不是一个Heart、一个Brain或一个Liver。相反,一个Person有一个Heart、一个Brain和一个Liver。因此,这些器官不应该暴露在一个Person的接口上。有了分层,客户端不会受到这些内部细节接口的影响。