Alex Murphy

Jun 20, 2020

4 min read

Open-Closed Principle

In this article, I am going to discuss the Open-Closed Principle with one real-time example. Please read our previous article before proceeding to this article where we discussed the Single Responsibility Principle with one real-time example. The letter O in SOLID stands for the Open-Closed Principle which is also known as OCP.

Here is the list of the blogs in this series:

  1. Understand SOLID Principle
  2. Single Responsibility Principle
  3. Liskov Substitution Principle
  4. Interface Segregation Principle
  5. Dependency Inversion Principle

What is the Open-Closed Principle?

The Open-Closed Principle states that “software entities such as modules, classes, functions, etc. should be open for extension, but closed for modification“.

The Open for extension means we need to design the software modules/classes in such a way that the new responsibilities or functionalities should be added easily when new requirements come. On the other hand, Closed for modification means, we should not modify the class/module until we find some bugs.

The reason for this is, we have already developed a class/module and it has gone through the unit testing phase. So we should not have to change this as it affects the existing functionalities. In simple words, we can say that we should develop an entity in such a way that it should allow its behaviour to be extended without altering its source code.

Implementation Guidelines for the Open-Closed Principle

  1. The easiest way to implement the Open-Closed Principle is to add the new functionalities by creating new derived classes which should be inherited from the original base class.
  2. Another way is to allow the client to access the original class with an abstract interface.
  3. So, at any given point of time when there is a change in requirement or any new requirement comes then instead of touching the existing functionality, it’s always better and suggested to create new derived classes and leave the original class implementation as it is.

Problems of Not following the Open-Closed Principle

If you are not following the Open-Closed Principle during the application development process, then you may end up your application development with the following problems

  1. If you allow a class or function to add new logic then as a developer you need to test the entire functionalities which include the old functionalities as well as new the functionalities of the application.
  2. As a developer, it is also your responsibility to tell the QA (Quality Assurance) team about the changes in advance so that they can prepare themselves in advance for regression testing along with the new feature testing.
  3. If you are not following the Open-Closed Principle, then it also breaks the Single Responsibility Principle as the class or module is going to perform multiple responsibilities.
  4. If you are implementing all the functionalities in a single class, then the maintenance of the class becomes very difficult.

Because of the above key points, we need to follow the open-closed principle while developing the application.

Let us understand the Open-Closed Principle with one example.

public class Invoice {  public void getInvoice(InvoiceType invoiceType) {    switch(invoiceType) {        case BasicInvoice:
System.out.println("Basic Invoice");
break;
case PremiumInvoice:
System.out.println("Premium Invoice");
break;
}
}

enum InvoiceType {
BasicInvoice,
PremiumInvoice
}
}

Here you can see, if one more invoice type comes in future then we need to add another case in switch within source code of above GetInvoice() method which violates the Open Close Principle.

For example,

public void getInvoice(InvoiceType invoiceType) {switch(invoiceType) {    case BasicInvoice:
System.out.println("Basic Invoice");
break;
case PremiumInvoice:
System.out.println("Premium Invoice");
break;
case BusinessInvoice:
System.out.println("Business Invoice");
break;
}
}

enum InvoiceType {
BasicInvoice,
PremiumInvoice,
BusinessInvoice
}
}

As you can see in the above code, here you can see, new BusinessInvoice comes then we have to modify our code by adding new case.

As per the Open-Closed principle, Instead of “MODIFYING”, we should go for “EXTENSION”.

If you want to follow the Open-Closed Principle in the above example, when a new invoice type needs to be added, then we need to add a new class. As a result, the current functionalities that are already implemented are going to be unchanged. The advantage is that we just only need to test and check the new classes.

interface Invoice {
void getInvoice();
}
class BasicInvoice implements Invoice { @Override
public void getInvoice() {

}
}

class PremiumInvoice implements Invoice {
@Override
public void getInvoice() {

}
}
public class InvoiceWithOpenClosePrinciple {

public static void main(String args[]) {

Invoice basicInvoice = new BasicInvoice();
basicInvoice.getInvoice();
Invoice premiumInvoice = new PremiumInvoice();
invoice.getInvoice();
}
}

As you can see in the above code, we have created classes BasicInvoice, PremiumInvoice. All these classes are inherited from the interface Invoice and they can override the GetInvoice() method. Tomorrow if another Invoice Type needs to be added and then we just need to create a new class by inheriting from the Invoice interface. The point that you need to keep focus is we are not changing the code of the Invoice interface.

Now, the Invoice is closed for modification. But it is open for the extension as it allows creating new classes deriving from the Invoice which clearly follow the Open-Closed Principle.

In the next article, I am going to discuss the Liskov substitution principle with a real-time example. I hope you understood the need and use of the Open-Closed Principle.

Thanks for reading this article ❤

If I got something wrong? Let me in the comments. I would love to improve.

Clap 👏 If this article helps you.

Follow me on Twitter.