Open Closed Principle in Java | SOLID Principles

The Open Closed principle (OCP) is one of the most important object oriented design principle. In this article, I am going to cover what is open closed principle. How to implement this design principle in our code or module.

The open closed principle is one of the five design principles of object-oriented design. These set of five principles are known as SOLID principles.

In my previous post, i have already explained single responsibility principle. In subsequent tutorials, I’ll cover rest of the principles.

Open Closed principle

The open closed principle states that the software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

The two key terms here are open for extension and closed for modification. Let’s understand the meaning of these two terms first.

Open for extension

Open for extension simply means extend the existing behaviour. We should design our classes in such a way so that behaviour or feature can be extended as the new requirement comes.

How we can extend the functionality

  1. By using inheritance. we create a superclass and for the different implementation we create it’s child classes which extends the functionality of a superclass.

2. By using interfaces. Here, instead of superclass we use interface that allow different implementations which we can easily substitute without changing the code.

Closed for modification

Closed for modification means once our module is developed and tested we should not modify it unless there is a bug or any change in that module. For any new requirement or feature, It should be closed for modification.

The idea behind this principle is to design our classes in such a way so that we will be able to incorporate new features/functionality without changing the existing code.

Open closed principle video tutorial

Why do we need open closed principle (OCP)

Let’s understand this through an example. Suppose, we have to design a module that processes payments from different modes (credit card, cash, gift card, etc.).

Initially, we have two sources of payments (cash and credit card). For this, we have created two classes one for accepting payment through cash and another to handle credit card payment.

CashPayment

CreditCardPayment

We also have one PaymentProcessor class which accepts payment mode. Then it invokes the method of the relevant class based on the mode of payment.

Does this code follows the open closed principle? The answer is no. Because, let’s say in future we have to support one more payment mode for this we need to change the payment processor class.

The code in PaymentProcessor class change with every new payment mode support. This is a clear violation of the open/closed principle.

Let’s understand what’s wrong in this code.

i) It clearly impacts the code stability. In our code, we are modifying the same class when we have to incorporate new payment mode. It means we have to retest again all the payment modes. We are compromising the code stability. Any new payment mode risk the stability of previous stable code.

ii) Every new if else block increases code complexity. For every new payment mode, we are adding if else block which increases code complexity and overtime code becomes unmanageable.

How to make code extensible

We can extend the behaviour either using Inheritance or Polymorphism.

The problem with inheritance is that it introduces tight coupling, if the subclasses depend on the implementation details of their parent class.

To address the problem of inheritance, Robert C. Martin redefined the Open/Closed Principle to the Polymorphic Open/Closed Principle. The objective is to use interfaces instead of superclasses. Using interfaces we can provide different implementations without changing the existing code.

Let’s refactor our code using interface. Let’s define an interface IPay which has only one method to accept payment. All the payment mode will implement this interface.

Credit card payment and cash payment implements IPay interface and defines acceptPayment method.

Similarly, When new payment mode is introduced (ex. gift card, etc.). We can implement them using separate class. New class just need to implement this interface.

Let’s see the PaymentProcessor class. In this processPayment() method it only accepts the reference of class which implements IPay interface and invoke it’s accept payment method.

Using this approach we are not modifying the existing stable code. We are extending the behaviour without impacting the existing functionality.

Tagged , , . Bookmark the permalink.

About WebRewrite

I am technology lover who loves to keep updated with latest technology. My interest field is Web Development.