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:
public class Cat {
Claw claw_;
public Cat(Claw claw) {claw = claw_;}
public final void scratch() {
if (claw_ != null) {
claw_.scratch(this);
}
}
}
This allows you to delegate the scratching logic to the contained Claw
object, 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.