What does it mean to build an application using inheritance and why do you need it? Obviously, you want some sort of class-like constructs that you can extend and overwrite which implicitly means you’ll have great code reusability and virtually no duplication.
Well yes… assume we’re designing some sort of game; let’s call it Farmyard; we’re going to need some animals, maybe a Duck and a Chicken and give them some basic actions.
Before you say anything… yes, chickens can swim (proof here)
As you can see, all of the animal classes have their own actions, but they also have shared (inherited) actions from their parent (Animal) class. At this point you might be thinking: “Well this just proves inheritance is clean and tidy. Nothing can go wrong here, now can it?”.
Right, well… please implement a Rubber Duck class (because your brilliant requirements demand one) and make it fit in this beautiful code we have.
You’ll go through the 5 stages of grief:
- Denial: No, you don’t need that… this if Farmyard!
- Anger: A rubber duck doesn’t even make sense, this is preposterous!
- Bargaining: What if it’s a rubber duck but it can also eat and sleep; would that be so bad?
- Depression: Oh man, these specifications are crazy; I can’t believe we’re even discussing this.
- Acceptance: OK, I’ll find a way to implement your stupid rubber duck… but I don’t like this at all!
You only have three classes and you’re already in trouble… so what can a Rubber Duck do? …we could say it can swim and quack (or at least float and make noises), but it definitely can’t eat, sleep or fly… so it can’t subclass Duck nor Animal for that matter. So what do you do now?
If you want to do it cleanly and not have any code duplication, you’ve realized by now that your system (simple as it may be) is improper, because it has at least one flaw… it makes assumptions. You should write your code in a way that doesn’t involve making speculation about what it can/will become.
Composition to the rescue!
What if we do it like this, break the system down into actions which can be assigned/grouped into objects… maybe something like this:
All of the actions have been defined as separate methods which receive a state. This state can hold multiple key: value pairs but for the sake of brevity we’re only passing in the name that our functions (Duck and RubberDuck) receive as a parameter.
Look at the simplicity of the code, we’re using Object.assign which is part of the ES6 specs. If you’re worried about browser compatibility, don’t be, libraries like jQuery, Underscore, Angular (and many others) have an equivalent for this called $.extend(), _.extend() and angular.extend(). You could even write your own version of the function in a few lines of code.
Our RubberDuck problem simply goes away without any complications:
- We gave it the ability to swim and quack by using the Object.assign method
- It’s different from a Duck in the sense that it can’t eat, sleep or fly
- We broke down our logic into functions which return a specific action
- Everyone is happy regardless of how utterly pointless a Rubber Duck is in the context of the game
Clean, clear, no code duplication, should be easy to maintain and document.
Repost – courtesy to: Radu B. Gaspar