Why the Open-Closed Principle is the one you need to know (OCP)

Image related to Open/Closed Principle

You should be able to extend the behavior of a system without having to modify that system.

Think about that very carefully. If the behaviors of all the modules in your system could be extended, without modifying them, then you could add new features to that system without modifying any old code. The features would be added solely by writing new code.

What’s more, since none of the old code had changed, it would not need to be recompiled, and therefore it would not need to be redeployed. Adding a new feature would involve leaving the old code in place and only deploying the new code, perhaps in a new jar or dll or gem.

Now you might be thinking how can we achieve extension without making any modifications to a jar or dll or gem?

The answer lies in abstraction. Once we start relying on abstractions then we many ways to apply the open-close principle. In .NET we can achieve this abstraction through Interfaces and Abstract classes.

When we want to add new behavior, then we need to write new functions and new classes and this helps a single class in focus on one thing and we end up with small, easier to maintain classes. Also when we write new classes then none of the existing code is dependent on this new code and hence unlikely to introduce a bug.

We can add seams to the applications which allow us to create the demarcation between different layers.

Approaches for achieving the Open/Closed principle

Parameters

We could pass some information as parameters which could help us avoid the modifications. For example, we create a simple program to clean up temporary files on my computer at 9 AM. Now I share this code on my blog and people start using it but soon people start asking for a simple modification of allowing the users to decide the time for the cleanup to run. Now if I would have allowed this time to be a user inputted parameter then my class and function would have not needed any modifications.

Inheritance

Inheritance is another way to achieve the open-close behavior. In inheritance we allow the child classes to change and extend the behavior without making any changes to the parent classes.

Composition

To achieve Composition we could use the Strategy pattern. The strategy pattern allows us to follow the plugin model where the class doing the work gets injected into the class that needs that behavior. In this case, we have a level of abstraction between the calling code and called code. In this type of approach, the Implementation class used Inheritance since that will inherit from the base for some implementation and the client class follows composition since it exposes itself for other classes to pass into itself.

Example

Let us take the example of a class that calculates the area of a rectangle

Rectangle image

To get the area of a rectangle we will pass the object of the Rectangle class and get the area back.

Rectangle area calculation

Now we would like to extend the AreaCalculator to calculate the area of a circle as well.

Circle image

So we will change the AreaCalculator to something like below. So depending on the shape we can calculate the area of the shape.

Area calculator for shapes

However if tomorrow we want to extend the AreaCalculator class to include another shape then we will have to modify the class again.

A solution that abides by the Open/Closed Principle

Now let us try to implement the AreaCalculator class following the Open / Closed principle. Let’s start by creating an abstraction for shape. We will create a class named shape that exposes a method Area.

Shape class diagram

Now, whenever we want to create a Shape we will inherit from this abstract class. Let us now create Rectangle and Circle classes inheriting from Shape. We will provide the individual implementation of the Area and also add the properties as applicable for each shape.

Rectangle class diagram Circle class diagram

Since each shape has its own implementation of Area so our AreaCalculator becomes much simpler and robust.

Updated AreaCalculator class

And since the new classes bring in their own implementations we do not need to modify the existing functionality because of the new behaviors that we add.

Final diagram

Add comment