Inheritance. Concrete classes. Reuse. A fantastic mix up.
TL;DR: Don't subclassify concrete classes
-
Bad Models
-
Coupling
-
Liskov Substitution Violation
-
Method overriding
-
Mapper fault
-
Subclasses should be specializations.
-
Refactor Hierarchies.
-
Favor Composition.
-
Leaf classes should be concrete.
-
Not leaf classes should be abstract.
class Stack extends ArrayList {
public void push(Object value) { … }
public Object pop() { … }
}
// Stack does not behave Like an ArrayList
// besides pop, push, top it also implements (or overrides)
// get, set, add, remove and clear
// stack elements can be arbitrary accessed
// both classes are concrete
abstract class Collection {
public abstract int size();
}
final class Stack extends Collection {
private contents[] ArrayList;
public Stack() {
contents = new long[maxSize];
}
public void push(Object value) { … }
public Object pop() { … }
public int size() {
return contents.size();
}
}
final class ArrayList extends Collection {
public int size() {
// ...
}
}
Overriding a concrete method is a clear smell. We can enforce these policies on most linters.
Abstract classes should have just a few concrete methods. We can check against a predefined threshold for offenders.
- Composition
Accidental sub-classification is the first obvious advantage for junior developers.
More mature ones find composition opportunities instead.
Composition is dynamic, multiple, pluggable, more testable, more maintainable and less coupled than inheritance.
Only sub-classify an entity if it follows the relationships behaves like.
After sub-classing the parent class should be abstract.
Code Smell 11 - Subclassification for Code Reuse
Software is a gas; it expands to fill its container.
Nathan Myhrvold
Software Engineering Great Quotes
This article is part of the CodeSmell Series.