A colleague of mine came up with a rule-of-thumb for choosing between creating a base class or an interface.
He says:
Imagine every new method that you are about to implement. For each of them, consider this: will this method be implemented by more than one class in exactly this form, without any change? If the answer is "yes", create a base class. In every other situation, create an interface.
For example:
Consider the classes
cat
anddog
, which extend the classmammal
and have a single methodpet()
. We then add the classalligator
, which doesn't extend anything and has a single methodslither()
.Now, we want to add an
eat()
method to all of them.If the implementation of
eat()
method will be exactly the same forcat
,dog
andalligator
, we should create a base class (let's say,animal
), which implements this method.However, if it's implementation in
alligator
differs in the slightest way, we should create anIEat
interface and makemammal
andalligator
implement it.
He insists that this method covers all cases, but it seems like over-simplification to me.
Is it worth following this rule-of-thumb?
Best Answer
I don't think that this is a good rule of thumb. If you are concerned about code reuse, you can implement a
PetEatingBehavior
which role is to define the eating functions for cats and dogs. Then you can haveIEat
and code reuse together.These days I see less and less reasons to use inheritance. One big advantage is the ease of use. Take a GUI framework. A popular way to design an API for this is to expose a huge base class, and document which methods the user can override. So we can ignore all the other complex things our application needs to manage, since a "default" implementation is given by the base class. But we can still customize things by reimplementing the correct method when we need to.
If you stick to interface for your api, your user has usually more work to do to make simple examples work. But API with interfaces are often less coupled and easier to maintain for the simple reason that
IEat
contains less information than theMammal
base class. So consumers will depend on a weaker contract, you get more refactoring opportunities, etc.To quote Rich Hickey: Simple != Easy