Stop Using Inheritance For "Code Reuse"
Let's talk about class design.
A Typical Approach
My computer science education took place in the 2000s, which means it was fostered in a world heavily focused on certain aspects of Object Oriented Programming (OOP). Introductory and even advanced courses at universities across the country were (and maybe still are?) tailored toward teaching students to think of their program designs in terms of real-world objects. Many a professor could be heard saying things like:
"Today we're writing a poker simulator, so what are some things that you have when you play poker? Yes, cards! So let's have a Card class. Uh huh, and a dealer, so we'll add a Dealer class. Hohoho, no, no Mr. Murphy, we won't need a Beer class!"
There's nothing wrong with this. Encapsulating functionality into classes is a great way to isolate components from each other. The problem that started arising was that the conversation would continue as:
Professor: "We're going to have the Dealer be in charge of shuffling the deck of cards. We're going to want different dealers with different shuffling algorithms. So how can we do that?"
Students: "A base class Dealer with subclasses that override shuffle!"
Professor: "Huzzah! A+'s for everyone and tenure for me!"
Students: "Huzzah!"
Let's make this concrete and see what their class design might look like:
https://gist.github.com/anonymous/8e227243aa9d85f0ba38
Inheritance As A Default Approach
Why use inheritance? When I ask interview candidates this question, the answer almost invariably comes back as "for code reuse". This is a fine thing to desire (reusing code is a nobel and often difficult goal), but there are lots of ways to reuse code, and inheritance is a very heavy-handed (and often very wrong) approach to this goal. Jumping to using inheritance to model specialized versions of an object is a dangerous habit, and unfortunately one that I am seeing more and more of lately.
Let's see what happens when we tack another duty onto our currently useless dealer. He's been sitting at the table shuffling for the last 6 hours, why doesn't he deal the freakin' cards already??
Depending on the game, our dealer might deal in different ways. For instance, in the Midwest of the US is obsessed with a game called Euchre where the dealer deals 5 cards to each player, but instead of dealing cards 1-by-1, she must choose to deal either 2 or 3 cards to each player. Weird, I know -- this game is best played while tipsy on pure corn alcohol. Let's implement the different dealing functions.
https://gist.github.com/anonymous/d160911d517a80919e16
So far so good. Just put the deal() function in our base-class Dealer and we can define it on a per-dealer basis.
https://gist.github.com/anonymous/b40ff062314285674383
On paper, this seems so straightforward -- a DirtyRottenScoundrelDealer is-a dealer, so why not just inherit from AbstractDealer and override the functions we want to do differently?
Well, as demonstrated above, the issue is that dealing and shuffling are orthoganal decisions and jumping to using inheritance to model our specialized dealer has comingled those two decisions. Any given dealer might be rotten and dealing Euchre, or they might be shitty at shuffling and dealing a regular game of poker. Or 7-card poker. Or that game where you use your junk-food-fueled forehead sweat to stick a card to your face. Do we need to create a DirtyRottenScoundrelDealerDealingEuchre subclass? Is it going to have a copy-paste of the Euchre dealing algorithm? Is this code reuse?
In the inheritance-heavy curricula of my formative years, the answer might have been to throw more inheritance at this. It might end up looking more like:
https://gist.github.com/anonymous/8aeb8657de3622628eb8
C++ lets us do this and get away with it for awhile longer. But in time the deadly diamond of death will consume us all.
Besides. Right when we finish creating our CrappyEuchreDealer, our Crappy7CardStudDealer, our GoodEuchreDealer, and our GoodForeheadGameDealer, the professor chimes in again:
"New function time! Add a cut() function to cut the deck!"
HOW MANY SUBCLASSES DO YOU WANT FROM ME?!
Policy-Based Design
Let's try a different approach. Policy-based Design!
The core idea behind Policy-based Design is to identify orthogonal concerns (algorithms in your program that don't affect one another) and just pass whatever implementation you want for each of those algorithms into your object. Instead of overrding functions using subclasses, you just plug in the functionality you want.
There are different ways to accomplish this. For very simple cases, you can get away with just passing functors or function objects into your class's constructor. Then it's just a matter of calling the appropriate functor:
https://gist.github.com/anonymous/6578aa5054a74ee44fa8
Let's look at some of the benefits of this:
We can choose between any shuffling strategy and any dealing style when we create our dealer
Any function that matches the expected signature can be used for our policy
We can store our algorithms somewhere common and reuse them (when sensible)
With orthogonal concerns separated, unit testing each implementation is easy
Test versions of each policy can be leveraged to aid in testing other aspects (for instance, a shuffle policy could put the cards in predefined order)
In more complicated situations, we may need to store some state, or a given policy may consist of multiple functions (think: serialize() and deserialize()). In cases like this, whipping out a little template metaprogramming works like a charm:
https://gist.github.com/anonymous/bd31ec81653cb7b117be
Wrapping Up
I don't want to preach about this topic as though it's the end-all be-all of class design. However, the approach that I do believe is an end-all be-all of class design is carefully considering your domain and weighing your options.
The more tools in your aresenal, the better equipped you'll be to tackle complicated problems. So just stick policy-based design principles next to composition and inheritance in your toolset and may the best tool win!











