Reputation: 2187
From presentation called How to Design a Good API and Why it Matters
I'm stuck on page 25 of the presentation in which says:
Public classes should not subclass other public classes for ease of implementation
And it gave us an examples (Java syntax):
Bad: Properties extends Hashtable
Stack extends Vector
Good: Set extends Collection
But why are those examples bad and good?
Upvotes: 4
Views: 100
Reputation: 180181
Bloch is distinguishing inheritance of interface from inheritance of implementation.
It is impossible to know from a slide deck what he said at this point in his presentation, but a typical argument for avoiding one public class inheriting from another is that it permanently ties the subclass to the superclass's implementation. For example, Properties
cannot ever implement its property storage in HashMap
form or any other form other than a HashTable
.
Another argument is that it couples the classes too tightly together. Modifications that would be beneficial to the superclass can break the subclass, or render its behavior worse.
A third argument is that the subclass inherits methods from the superclass that may not make sense for it, or may do so in the future if the methods are added to the superclass. For example, because Stack
extends Vector
, it is possible to examine arbitrary elements below the top one, and even to add, remove, or modify internal elements. This one applies to some extent also to inheritance of interface, but it is not usually as much of a problem in that case.
The first two arguments remain applicable to some extent even when the super- and subclasses have an is-a relationship.
Upvotes: 0
Reputation: 9816
Because a Properties
is not a Hashtable
, and they shouldn't be used interchangeably, i.e., you don't want users to use Properties
where they only need Hashtable
. Same for Stack
vs Vector
.
Good design should strive for simplicity of API. If you are designing a Stack
, you should basically only provide the push
and pop
methods. Publicly inheriting from Vector
leaks an implementation detail that the user does not need to know. Beside the confusion, this means you can never change the implementation! So if tomorrow Vector
gets deprecated (which I believe it actually is at this point), you are still stuck with a Stack
that uses it because your clients might expect it. Changing the implementation would violate backward compatibility, which is another design goal.
Note that the example above is not random. Both Vector
and Hashtable
are classes that are considered obsolete (see the last comments here and here). These classes have some design flaws and were replaced by ArrayList
and HashMap
or similar others. This makes classes that inherit from them obsolete as well. If instead of inheriting you used composition, you could easily swap Vector
and Hashtable
for their modern counterparts without affecting any user.
On the other hand, Set
is a Collection
. That is, if some code specifies that it needs some kind of Collection
, the user is free to provide a Set
(or a List
or whatever). This gives more flexibility to the API if there are no specific requirements on what this collection should provide (no random access for example).
Upvotes: 5
Reputation: 1378
Inheriting from a class is typically thought of as implementing an "is-a" relationship.
Is a collection of properties a hashtable? No, not really. The hashtable is an implementation detail, not a fundamental characteristic of "Properties". This implies that you should be using aggregation, like so:
class Properties {
private HashTable mPropertyTable;
}
The same goes for Stack and Vector. A Stack isn't a special kind of Vector, so the Vector should be a member of the Stack used for implementation only.
Contrast this with Set deriving from Collection. Is a Set a type of Collection? Yes, it is, so in this case inheritance makes sense.
Upvotes: 0