Why avoid the final keyword?-Collection of common programming errors

I couldn’t disagree more. Class hierarchies make sense for concrete classes when the concrete classes know the possible return types of methods that they have not marked final. For instance, a concrete class may have a subclass hook:

protected SomeType doSomething() {
return null;
}

This doSomething is guarenteed to be either null or a SomeType instance. Say that you have the ability to process the SomeType instance but don’t have a use case for using the SomeType instance in the current class, but know that this functionality would be really good to have in subclasses and most everything is concrete. It makes no sense to make the current class an abstract class if it can be used directly with the default of doing nothing with its null value. If you made it an abstract class, then you would have its children in this type of hierarchy:

  • Abstract base class
    • Default class (the class that could have been non-abstract, only implements the protected method and nothing else)

You thus have an abstract base class that can’t be used directly, when the default class may be the most common case. In the other hierarchy, there is one less class, so that the functionality can be used without making an essentially useless default class because abstraction just had to be forced onto the class.

  • Default class

Now, sure, hierarchies can be used and abused, and if things are not documented clearly or classes not well designed, subclasses can run into problems. But these same problems exist with abstract classes as well, you don’t get rid of the problem just because you add “abstract” to your class. For instance, if the contract of the “doSomething()” method above required SomeType to have populated x, y and z fields when they were accessed via getters and setters, your subclass would blow up regardless if you used the concrete class that returned null as your base class or an abstract class.

The general rule of thumb for designing a class hierarchy is pretty much a simple questionaire:

  1. Do I need the behavior of my proposed superclass in my subclass? (Y/N) This is the first question you need to ask yourself. If you don’t need the behavior, there’s no argument for subclassing.

  2. Do I need the state of my proposed superclass in my subclass? (Y/N) This is the second question. If the state fits the model of what you need, this may be a canidate for subclassing.

  3. If the subclass was created from the proposed superclass, would it truly be an IS-A relation, or is it just a shortcut to inherit behavior and state? This is the final question. If it is just a shortcut and you cannot qualify your proposed subclass “as-a” superclass, then inheritance should be avoided. The state and logic can be copied and pasted into the new class with a different root, or delegation can be used.

Only if a class needs the behavior, state and can be considered that the subclass IS-A(n) instance of the superclass should it be considered to inherit from a superclass. Otherwise, other options exist that would be better suited to the purpose, although it may require a little more work up front, it is cleaner in the long run.