Continuing on our series on SOLID development principles, in this guide I’m going to walk through the: open closed principle.
For some reason or another developers seem to struggle understanding this SOLID element more than any of the others. With that in mind I’m going to give a dead simple explanation of how the open closed principle followed by an example.
I think that once you see how powerful this concept is you’ll fall in love with it. Because at it’s core it allows you to scale your code without having to worry about wasting time on legacy classes.
Open Closed Principle Definition
A dead simple explanation of the open closed principle is this:
Software elements (classes, modules, functions, etc.) should be open for extension, but closed for modification
Essentially this means that you should build your classes in a way that you can extend them via child classes. AND that once you’ve created the class it no longer needs to be changed.
The original concept was credited to Bertrand Meyer when he coined the term back in 1988 in his book Object Oriented Software Construction.
Surprisingly Challenging Task
If you’ve never attempted this design pattern the concept may seem straightforward. However I think you’ll find this is a skill that takes practice and repetition (much like any other advanced development task).
Open Closed Principle Example
To understand how the open closed principle works let’s look at a practical example.
The Naive Approach
I’ve created an
OrderReport class that contains some attributes such as
total. In addition to the attributes the class also contains a couple of methods.
invoicemethod that prints out the details associated with an order.
- Along with a
bill_of_ladingmethod that prints out the order report for shipping purposes.
If we run the program you’ll see that it works perfectly fine and prints out the values for each method.
I Don’t Like Change!!!
However this class has a nasty secret: it doesn’t like change. Let’s imagine that we’re asked to update the
bill_of_lading method to also print out the customer address?
This may not seem like a major change, however in order to accommodate the request we’ve had to make four changes.
One of the changes is even requiring us to pass an
address to the class as a required argument. This means that even when all we need is an
invoice (that doesn’t care about the customer
address) we have to include the additional element.
Also of note is that this was a very small change. Imagine what would happen if we needed to build a feature such as including a QR code?
So not only is this code not very scalable, it’s breaking the open close principle. A well written class should not have to be re-written in order to integrate a new feature like having an
A Better Way
Thankfully we can clean up this entire class and follow the open closed principle by leveraging Object Oriented inheritance.
In this code I’ve pulled out the invoice and bill of lading components into their own classes that inherit from the
This refactor has a number of benefits:
- It follows the open closed principle because now when we have to build new features for
bill of ladingswe don’t have to touch the
OrderReportclass. Therefore we can say that the parent class is closed.
- Additionally, since we split up the two components, whenever we create an
invoicewe don’t have to pass in an unnecessary
addresselement. This removes code that’s not needed and that could lead to confusion later on down the road.
- Lastly our program not only follow the open closed principle, but now our classes also follow the single responsibility principle. Notice how each class has a specific focus? (aka a single responsibility)
If you run this code you’ll see that it still has the same behavior as before, but now our code is much more scalable and dare I say SOLID?
I hope that this has been a helpful guide to understanding the open closed principle and that you can apply it to your own programs. In the resource section I’ve included a number of links where you can explore this topic in more detail.