来自名为How to Design a Good API and Why it Matters的演示文稿
我停留在演示文稿的第25页,其中说:
为了方便起见,公共类不应该为其他公共类创建子类 实施
它给了我们一个例子(Java语法):
Bad: Properties extends Hashtable
Stack extends Vector
Good: Set extends Collection
但为什么这些例子不好又好?
答案 0 :(得分:4)
因为Properties
不是 Hashtable
,并且它们不应互换使用,即您不希望用户使用Properties
他们只需要Hashtable
。 Stack
与Vector
相同。
良好的设计应该努力简化API。如果您正在设计Stack
,则基本上应该只提供push
和pop
方法。公开继承自Vector
泄漏了用户不需要知道的实现细节。除了困惑,这意味着您可以永远更改实施!因此,如果明天Vector
被弃用(我相信它实际上已经在这一点上),那么您仍然会遇到使用它的Stack
,因为您的客户可能会期望它。更改实现会违反向后兼容性,这是另一个设计目标。
请注意,上面的示例不是随机的。 Vector
和Hashtable
都是被视为过时的类(请参阅上一条评论here和here)。这些类有一些设计缺陷,被ArrayList
和HashMap
或类似的其他类替换。这使得从它们继承的类也过时了。如果不是继承您使用的合成,您可以轻松地将Vector
和Hashtable
换成现代版本,而不会影响任何用户。
另一方面,Set
是 Collection
。也就是说,如果某些代码指定它需要某种Collection
,则用户可以自由提供Set
(或List
或其他任何内容)。如果对此集合应提供的内容没有特定要求(例如,无随机访问),则可为API提供更大的灵活性。
答案 1 :(得分:0)
从类继承通常被认为是实现了一个" is-a"关系。
属性集合是哈希表吗?不,不是真的。哈希表是一个实现细节,而不是"属性"的基本特征。这意味着您应该使用聚合,如下所示:
class Properties {
private HashTable mPropertyTable;
}
Stack和Vector也是如此。堆栈不是一种特殊的Vector,因此Vector应该只是用于实现的Stack的成员。
将此与来自Collection的Set派生对比。是一个集合类型?是的,它是,所以在这种情况下继承是有道理的。
答案 2 :(得分:0)
Bloch区分接口的继承和实现的继承。
从幻灯片中知道他在演讲中的这一点上是不可能知道的,但是避免一个公共类从另一个继承的典型论点是它永久地将子类与超类的实现联系起来。例如,Properties
无法永远以HashMap
形式或HashTable
以外的任何其他形式实现其属性存储。
另一个论点是它将这些类紧密地结合在一起。对超类有益的修改可能会破坏子类,或使其行为更糟。
第三个参数是子类从超类继承可能对它没有意义的方法,或者如果将方法添加到超类中,将来可能会这样做。例如,因为Stack
扩展了Vector
,所以可以检查顶部元素下方的任意元素,甚至可以添加,删除或修改内部元素。这个在某种程度上也适用于接口的继承,但在这种情况下通常不会出现问题。
前两个参数在某种程度上仍然适用,即使超类和子类具有is-a关系。