Introducing (in this Chapter):
- Inheritance anti-patterns
Inheritance anti-patterns: Abuses of implementation inheritance
As we have seen (in the preceding chapter), inheritance is very powerful and can provide significant benefits in programming. However, there are times when it is misused, leading to problems that could possibly be avoided. This section considers some of these misuses.Violating the IsA rule
Many of the situations where class inheritance is overused and/or incorrectly used can be traced back to a violation of the IsA rule, with the consequence that the subclassing invalidates the subtyping. The first anti-pattern is a direct consequence of breaking the IsA relationship.Anti-Pattern 7.1 Incomplete (constrained) subclass
This anti-pattern is also referred to as false generalisation. In a particular situation, a subclass (ClassB) may require only part of the functionality of the superclass (ClassA). However, the entire superclass is inherited and visible, since it is not possible to restrict its visibility . This means that inherited operations unrelated to the subclass become feasible, possibly with disastrous results.Note: In neither Delphi nor C Sharp (C#) can a subclass reduce the visibility of any superclasss data or methods without resorting to overriding, a situation that leads to anti-pattern 7.2. C++ provides a mechanism within the language to restrict visibility but this should be used carefully.
Therefore, to prevent potentially erroneous operation, revise the hierarchy so that the semantics of the application are maintained. There are at least three possibilities:
The subclass is a restricted version of the superclass: In this case one can consider inverting the hierarchy so that the more restricted class becomes the superclass.
Considerable commonality, but each has characteristics not found the other: In this case create an artificial parent class to house all the common functionality. Derive the subclasses from this, each one implementing its additional characteristics (ie characteristics not implemented as common characteristics in the parent). In the previous chapter neither TEmployeeCard nor TVisitorCard contains all the features of the other. This is resolved by moving the shared attributes and behaviour to a specially constructed parent of both classes.
Only slight commonality between the classes: Compose ClassB from ClassA This allows ClassB to avoid reimplementing the shared behaviour by delegating the shared behaviour to ClassA (instead of inheriting it from ClassA). Delegation and composition are discussed in part 8.
Anti-Pattern 7.2 Limiting visibility
One of the problems when a subclass is a restricted version of the superclass is that the subclass exposes aspects of the superclass that are not related to the subclass. (The subclass cannot reduce the visibility of the superclass.) Anti-pattern 7.1 provides three possible solutions to this problem. A fourth possibility exists, but that creates its own set of undesirable consequences. One can, for all the behaviour in ClassA that is not relevant to ClassB, provide an overriding method in ClassB that invalidates the inappropriate matching method in ClassA. If Method1 in ClassA does not apply to ClassB, ClassB overrides Method1 and performs a null or different operation or throws an exception. So, ClassB declares a method of the following format:There are several potential problems in this approach. To limit visibility like this requires constant vigilance and intervention by the programmer, who must identify and override all the inherited methods that are not appropriate in the subclass. Leaving out some of these overrides can lead to serious errors. Invalidating or changing the behaviour in the subclass also affects the semantics, and the subclass no longer IsA superclass. Since the subclass is now not a proper subtype of the superclass, the subclass can no longer substitute for the superclass for the invalidated or changed operations. If the programmer attempts to use polymorphic substitution, this can lead to serious errors.procedure ClassB.Method1;
begin
{ Throw Exception; }
// OR
{ Null operation; }
// OR
{ Different operation; }
end
Therefore, in a subclass do not invalidate any inherited method or override it in a way inappropriate to the superclass since doing so will destroy the subtyping and make polymorphic operations error-prone. Instead, restructure the hierarchy along one of the possibilities suggested as solutions in anti-pattern 7.1.

