- Read Tutorial
- Watch Guide Video
Poorly Constructed Code
We’ll begin by reviewing a real world example of a poorly written feature. I’m going to use the Ruby programming language for this example, however inheritance works the same across most programming languages. Here we have an Invoice class that, for the sake of this example, simply prints out a summary of the invoice. The class encapsulates a total, customer, and category value. Additionally the class has a summarize method that calls those values and prints them out.
As far as a traditional class goes, this Invoice class works perfectly fine. However, as it usually occurs, what happens if you’re asked to build a feature for printing out a shipping label. If you don’t use inheritance then your code may look something like this.
With the new ShippingLabel class we need a total and attribute value. Additionally we’re printing out a label that contains the values from the class. There are a number of issues with this implementation, the most glaring is that the Invoice and ShippingLabel classes have almost identical values. By creating two separate classes this code is breaking the DRY (Don’t Repeat Yourself) principle. If the requirements change where invoices and shipping labels need to both print out an address, city, state, and postal code you’ll need to add the identical attributes to multiple places in the application. Eventually this type of application design would lean to a very convoluted codebase that would be nearly impossible to maintain.
Don’t worry though, this is where the principle of inheritance comes in to play.
Object Oriented Inheritance Tutorial
In order to refactor this code we’re going to perform two tasks:
- Use inheritance so that the Shipping Label class will be a child class of the Invoice class.
- Refactor the Invoice class to it’s more flexible and will work better as a parent class.
Using inheritance in Ruby is relatively straightforward. In our class definition we simply declare that the ShippingLabel class inherits from the Invoice class, as shown here.
As you can see, by having the ShippingLabel class inherit from Invoice we were able to remove the initialize method and associated attribute declarations. This implementation has removed the duplicate code we had earlier, so it’s looking better. However there’s one issue with our program now. If you notice when we create a shipping label we need to add in the category, because the Invoice class requires it. However it would be a poor design decision to require shipping labels to be instantiated with an attribute they don’t need. With this in mind let’s move onto refactoring the Invoice class to make it more flexible.
Most languages have the ability to declare that some attributes in a class can be optional. In the code below I’ve removed category from the attribute argument list and now it’s simply an optional value.
With this implementation, when we create a new shipping label we don’t have to include any values that would be unnecessary.
For further reading on Inheritance I highly recommend “Practical Object-Oriented Design in Ruby: An Agile Primer” by Sandi Metz. I hope that this has been a helpful object oriented inheritance tutorial and will help you improve your code design decisions.
Practical Object-Oriented Design in Ruby: An Agile Primer
Please note that this book is not free and is working with the Ruby programming language. If you would like to check it out, feel free, but it is not required.