I am in a situation very similar to what Steve McConnell’s in Code Complete has mentioned . Only that my problem is based of Vehicles and Trike happens to be on that by law falls in the category of Cars . Cars had four wheels until now . Any way my domain is unnecessarily complex so it is easy to stick with cats example below.
Be suspicious of classes that override a routine and do nothing inside
the derived routine This typically indicates an error in the design of
the base class. For instance, suppose you have a class Cat and a
routine Scratch() and suppose that you eventually find out that some
cats are declawed and can’t scratch. You might be tempted to create a
class derived from Cat named ScratchlessCat and override the Scratch()
routine to do nothing. This approach presents several problems:It violates the abstraction (interface contract) presented in the Cat
class by changing the semantics of its interface.This approach quickly gets out of control when you extend it to other
derived classes. What happens when you find a cat without a tail? Or a
cat that doesn’t catch mice? Or a cat that doesn’t drink milk?
Eventually you’ll end up with derived classes like
ScratchlessTaillessMicelessMilklessCat.Over time, this approach gives rise to code that’s confusing to
maintain because the interfaces and behavior of the ancestor classes
imply little or nothing about the behavior of their descendants.The place to fix this problem is not in the base class, but in the
original Cat class. Create a Claws class and contain that within the
Cats class. The root problem was the assumption that all cats scratch,
so fix that problem at the source, rather than just bandaging it at
the destination.
According to the text from his great book above . Following is bad
Parent Class does not have to be abstract
public abstract class Cat {
public void scratch() {
System.out.println("I can scratch");
}
}
Derived Class
public class ScratchlessCat extends Cat {
@Override
public void scratch() {
// do nothing
}
}
Now he suggests creating another class Claws, but I do not understand how can I use this class to avoid the need for ScratchlessCat#Scratch.
You would still have a
scratch()method, but it will not be overridden by the derived classes:This allows you to delegate the scratching logic to the contained
Clawobject, if present (and not scratch if there are no claws). Classes derived from cat have no say in the matter on how to scratch, so no need to create shadow hierarchies based on abilities.Also, because the derived classes cannot change the method implementation, there is no problem of them breaking the intended semantics of the
scratch()method in the base class’s interface.If you take this to the extremes, you might find that you have a lot of classes and not many derivations — most logic is delegated to the composition objects, not entrusted to the derived classes.