Tuple subclassing should only be used for
is-a relationships; for example, a car
is a vehicle, and a circle
is a shape.
Anti-pattern #1: subclassing for has-aSubclassing should not be used for
has-a relationships. For example, if a shape
has a color, then
shape should not subclass
color. Using tuple subclassing in inappropriate situations leads to code which is more brittle and less flexible than it should be.
For example, suppose that
shape inherits from
color:
TUPLE: color r g b ;
TUPLE: shape < color ... ;
Now, the implementation of
shape depends on a specific representation of colors as RGB colors. If a new generic color protocol is devised which also allows HSB and YUV colors to be used, the shape class will not be able to take advantage of them without changes. A better approach is to store the color in a slot:
TUPLE: rgb-color r g b ;
TUPLE: hsv-color h s v ;
...
TUPLE: shape color ... ;
The
delegate library provides a language abstraction for expressing has-a relationships.
Anti-pattern #2: subclassing for implementation sharing onlyTuple subclassing purely for sharing implementations of methods is not a good idea either. If a class
A is a subclass of a class
B, then instances of
A should be usable anywhere that an instance of
B is. If this property does not hold, then subclassing should not be used.
There are two alternatives which are preferred to subclassing in this case. The first is
Mixin classes.
The second is to use ad-hoc slot polymorphism. If two classes define a slot with the same name, then code which uses
Slot accessors can operate on instances of both objects, assuming the values stored in that slot implement a common protocol. This allows code to be shared without creating contrived relationships between classes.
Anti-pattern #3: subclassing to override a method definitionWhile method overriding is a very powerful tool, improper use can cause tight coupling of code and lead to difficulty in testing and refactoring. Subclassing should not be used as a means of "monkey patching" methods to fix bugs and add features. Only subclass from classes which were designed to be inherited from, and when writing classes of your own which are intended to be subclassed, clearly document what subclasses may and may not do. This includes construction policy; document whether subclasses should use
new,
boa, or a custom parameterized constructor.
See alsoParameterized constructors