Open-Closed Principle

The Open-Closed Principle is a component of The SOLID Principles. These principles can help you write software that is easy to extend and maintain whilst also avoiding code smells and bad design in your codebase. The open-closed principle states that any object should be open for extension but closed for modification, you should be able to add functionality to an object without having to modify its source code. This probably makes zero sense, as you must modify the code to add functionality. However, these principles are for the object-orientated programming paradigm. Within OOP we can use inheritance to extend the functionality of objects without having to change the base class source code. If you don’t understand inheritance or want a refresher please check out this post first – What is Inheritance?

The below code shows a simple class called Person that contains two fields, ‘firstname’ and ‘lastname’. I have ommitted the getters and setters from this code snippet and all other snippets on this post as those are not important in regard to what we will be discussing.

We can maintain the open-closed principle by creating another class and extending it from the Person base class. This allows adding functionality, or additional fields, to the class without having to modify the original base class source code. This makes our base class closed to modification, as we haven’t change the code, but open for extension, as we have inherited it’s functionality and fields and added to it.

Let’s look at an example that breaks this principle. Below we have another simple class called Shape which has two fields, the width and height. We are going to use this class as our base class, so we won’t change it or modify it but we will use inheritance to extend the functionality.

We can now create another class called Rectangle to extend on this behaviour and add a ‘getArea’ method. This allows us to calculate the area of a rectangle, and we don’t have to re-create the ‘width’ and ‘height’ fields as we have inherited them from the base class. This keeps in line with the open-closed principle, we haven’t broken it yet.

If we create another child of the Shape class to handle circles it starts to not make sense. Circles do not have a width and height, they have a radius. We could stay with the width and height fields and still make this work, as we can still work out the area of the circle. However, this starts to make our model more complicated and harder to maintain. To make this new class make sense in our model we would probably have to change our base class to allow the difference in fields. Think about what would happen if we added a Triangle class or a Hexagon class. Could we add them without changing the base class or would we have to change the Shape class for them to make sense? Changing the base class breaks the open-closed principle, as we have now modified our base class.

The examples shown in this post are very simple examples to convey the open-closed principle in an easy to understand way. It is important to note that sometimes you do have to refactor your code, or your base class, to add functionality. For example, when you are first building your software or your service you will be constantly changing the model and refactoring your code due to bug fixes and adding functionality. This is just a general rule when adding functionality to an existing or more established codebase. To be summarised and put simply, when adding a subclass of any class or interface you shouldn’t have to change the parent class or interface.

Leave a Reply