Effective Java 2nd Edition, Item 16: Favor composition over inheritance:
Inheritance is appropriate only in circumstances where the subclass really is a subtype of the superclass. In other words, a class B should only extend a class A only if an "is-a" relationship exists between the two classes. If you are tempted to have a class B extend a class A, ask yourself this question: Is every B really an A? If you cannot truthfully answer yes to this question, B should not extend A. If the answer is no, it is often the case that B should contain a private instance of A and expose a smaller and simpler API; A is not an essential part of B, merely a detail of its implementation.
There are a number of obvious violations of this principle in the Java platform libraries. For example, a stack is not a vector, so Stack
should not extend Vector
. Similarly, a property list is not a hash table, so Properties
should not extend Hashtable
. In both cases, composition would have been preferrable.
The book goes in greater detail, and combined with Item 17: Design and document for inheritance or else prohibit it, advises against overuse and abuse of inheritance in your design.
Here's a simple example that shows the problem of Stack
allowing un-Stack
-like behavior:
Stack<String> stack = new Stack<String>();
stack.push("1");
stack.push("2");
stack.push("3");
stack.insertElementAt("squeeze me in!", 1);
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
// prints "3", "2", "squeeze me in!", "1"
This is a gross violation of the stack abstract data type.
See also
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…