Open-Closed Principle (OCP)

Shashi Kant
3 min readJul 6, 2023

--

“Software entities must be open for extension but closed for modification.”

Introduction

In our journey to mastering design principles, we are heading to learn one of the core principles of software development, Open Closed Principle (OCP). In the journey of software development, one the major problem is to make software maintainable with reasonable costs because as the software grows, new features are required. While adding these features, we may end up changing the existing code so that these new features work correctly but that may end up messing the already working features. To avoid this type of clash, OCP was born.

Open-Closed Principle

This principle encourages developers to write software entities like classes and modules in a way that allows them easily extend but prohibit them to modify. By applying this principle, we can achieve a balance between the stability and flexibility to deliver a system which is easily maintainable.

How can we apply the principle?

  1. Abstraction and Polymorphism: We can define interfaces and abstract classes that has the common methods to be used in different classes. In this way, whenever we need a new version of same method or class, we simply inherit the base class and override method with new implementation. In this way, our code becomes easily extensible without modifying the already working features.
  2. Dependency Injection: Inheriting a concrete class is not always a good idea and even sometimes in the case abstract ones too. As many developers suggest to use composition over inheritance if the inheriting class is not exact type of the base class. We can do that by injecting the class in the methods of the another class or while instantiating it. In this way, we can easily replace or the extend the functionalities without modifying the code that depends on them.
  3. Design Patterns: There are various design patterns which encourage the use of OCP. Few ones are strategy, decorator and observer patterns. These design patterns are designed in such a way that they provide us tool to achieve new features without modifying the existing code.

Example

Suppose we need to implement a push notification features which can push different type of notifications to the users. If we create a simple class Notification and use it to push all the notifications, it breaks OCP as for every new type of notification, we will be modifying the code. To achieve a good design, we can create a base abstract class or a interface and use that to define the implementations of different type of notifications.

import abc

class AbstractNotification(abc.ABC):
@abc.abstractmethod
@classmethod
def __init__(self, message):
...

@abc.abstractmethod
def push(self):
...

class NewOrderNotification(AbstractNotification):
def __init__(self, message):
...

def push(self):
...

class OrderCancelNotification(AbstractNotification):
def __init__(self, message):
...

def push(self):
...

In the above code, we created an abstract class and inherited that to provide different implementations. In this way, whenever we need a new type of notification, we simply inherit the abstract class and provide new implementation. Although, Python is duck typed language so it may seem useless to define the abstract class but still it can give developers a good self documentation of the every notification class.

Synergy with other SOLID Principles

SOLID principles are such principles that they are in synergy with others. Often breaking one of them, will cause to break some of others. Open closed principle is also in great synergy with others. Since we have already studied the SRP, so I will be talking about these now. In our previous example, if we were have implemented that with single notification class, that simply breaks the SRP too as the single class was given responsibility of handling many types of notifications.

Conclusion

OCP is one of the key principles while writing code as it tends to provide us a balance between stability of already written code and flexibility of adding new code which gives us a maintainable code which can add accept new features easily. In the next blog, we will be going through another important principle, Liskov’s Substitution Principle (LSP).

--

--

Shashi Kant

Backend developer with professional experience in Python, TypeScript and Rust.