What is a detailed explanation of the "Subclass only where it makes sense" argument?

From a presentation titled How to Build a Good API and Why It Matters

I am stuck on page 25 of the presentation, which says:

Public classes should not subclass other public classes for ease of implementation

And he gave us examples (Java syntax):

Bad:    Properties extends Hashtable 
        Stack extends Vector

Good:   Set extends Collection

      

But why are these examples good and bad?

+3


source to share


3 answers


Since Properties

it is not Hashtable

, and they should not be used interchangeably, i.e. you don't want users to use Properties

where they only need Hashtable

. The same goes for Stack

vs Vector

.

Good design should strive for API simplicity. If you are designing Stack

, you should basically only provide methods push

and pop

. Public inheritance from Vector

removes implementation details that the user doesn't need to know. Confusion aside, this means you can never change the implementation! So if tomorrow Vector

becomes obsolete (in my opinion it really is now), you still stick Stack

with who uses it because your customers might expect it. Changing the implementation will break backward compatibility, which is another design goal.



Please note that the above example is not random. Both Vector

and Hashtable

are classes that are considered obsolete (see. Last comments here and here ). These classes have some design flaws and have been replaced by ArrayList

and HashMap

or similar others. This makes classes that inherit from them deprecated as well. If instead of inheritance you use composition, you could easily change Vector

and Hashtable

for their modern counterparts, without affecting any user.

On the other hand, it Set

is Collection

. That is, if some code indicates that it needs some Collection

, the user can provide Set

(or a List

or something else). This gives a lot of flexibility to the API as long as there are no specific requirements for what the collection is supposed to provide (for example, no random access).

+4


source


Inheriting from a class is usually seen as implementing an "is-a" relationship.

Is a property set a hash table? No, not at all. The hash table is an implementation detail, not a fundamental property of "Properties". This means that you have to use aggregation, for example:

class Properties {
    private HashTable mPropertyTable;
}

      



The same goes for Stack and Vector. Stack is not a special kind of Vector, so Vector must be a member of an implementation-only stack.

Contrast this with a Set sourced from the collection. Is a set a collection type? Yes, it does, so inheritance makes sense in this case.

0


source


Bloch distinguishes interface inheritance from implementation inheritance.

It is impossible to know from the slide deck what he said at this point in his presentation, but the typical argument for avoiding inheriting one public class from another is that it constantly binds the subclass to the superclass's implementation. For example, Properties

it cannot implement its property store in a form HashMap

or in any other form other than HashTable

.

Another argument is that it ties the classes together too tightly. Modifications that would be useful to the superclass can break the subclass or worsen its behavior.

The third argument is that the subclass inherits methods from the superclass, which may not make sense to it, or might do so in the future if methods are added to the superclass. For example, since Stack

extends Vector

, you can view arbitrary elements below the top and even add, remove, or modify inner elements. This applies to some extent to interface inheritance, but in this case it usually isn't that much.

The first two arguments remain somewhat applicable even if super- and subclasses have an is-a relationship.

0


source







All Articles