There's a rule of thumb I was taught long ago that one shouldn't
derive one concrete class from another. Â I've found it to be excellent
advice. Â I can't explain particularly well why doing so is a bad idea
in general, but whenever I've been tempted to break the rule, I've
found that creating an abstract superclass (or a hierarchy of such
superclasses) from which all concrete classes are derived has solved
problems the concrete-derived-from-concrete design created. Â I don't
think it's far wrong to say:
 Declare all concrete classes as final.
.... if you are ominous
If you are ominous then this idea is great. I'd bet you are not. In
fact declaring everything as final is worse than most things you can
do to cripple program development. IMO every time you are
_introducing_ final you have to think deeply. You propose something
opposite, final by default, which effectively throws away the open-
closed principle which lies at the foundation of OOP. If no concrete
class can be redefined, then either your implementation has to be
perfect, so no need ever arises to modify its behavior, or you provide
no implementations at all. Both cases are quite useless from your
clients perspective. Consider: Checkbox <- Button, SecureConnection <-
Connection. Now you are proposing to reject similar cases, so every
Button implementation will have to either be catch-all scheme (not
possible) or go to great lengths to abstract every functionality by
means of composition/decoration (either not possible or hardly doable
considering that every contained type still suffers from the same
illness - one concrete type only). Furthermore, in my opinion program
maintenance is done mostly "near leaves" (of inheritance tree) - most
ADTs have their implementations already defined at this stage.