SOLID — OPEN/CLOSED PRINCIPLE (OCP)

Berkay Ergun
4 min readDec 10, 2023

--

Hello, in this article I will explain the Open/closed principle, which is the 2nd letter of SOLID principles. If you do not know what SOLID is, you can access it from the relevant link.

The Open/Closed Principle (OCP) is one of the SOLID principles and aims to ensure extensibility in software design. This principle advocates that a class should be closed to modification (existing code closed for modification), but open for extension (open for extension) to add new functionality.

So what do Open and Closed mean?

  1. Closed for Modification: Existing code should be closed to modifications to existing classes or modules. That is, it is important not to modify existing working code. This ensures the stability and reliability of the existing system.
  2. Open for Extension: It should be possible to add or change new functionality in the system. When new requirements arise, you should be able to make changes to the system by adding new code instead of replacing existing code.

OCP requires that a class or function should preserve existing features, i.e. not change its behavior, and should be able to gain new features.

Changing the code is, as the name implies, changing the code. It is the processing of the current version according to the new requirement instead of the existing one.

Extending the code: The ability to add future behavior to the application according to the new requirement without changing the code.

A code is ideal if it is open to expansion and closed to change.

Example without using the Open/Closed Principle

You want to integrate a bank into your system. Whichever bank the user chooses, money should be sent from that bank. Let’s code this without using OCP.

class BankX
{
public void SendMoney(string accountNumber, decimal amount)
{
// Send money using Bank A
Console.WriteLine($"Sending {amount} to {accountNumber}");
}
}
class BankY
{
public void SendMoney(string accountNumber, decimal amount)
{
// Send money using Bank B
Console.WriteLine($"Sending {amount} to {accountNumber}");
}
}
public class MoneySenderNonOCP
{
public void SendMoney(string accountNumber, decimal amount)
{
var bank = new BankX();
bank.SendMoney(accountNumber, amount);

bank = new BankX();

bank.SendMoney(accountNumber, amount);
}
}

Without using the OCP principle, as you can see, we have to re-new for each bank, in the function that fulfills the main responsibility. It is not a problem to do it here. But one day in the future, when a change comes, you will have to rewrite this function. This is where the real cost starts.

When adding a new bank here, we will delete and replace the old bank. But this can affect many places and leave us in a very difficult situation. So we need to write our code in an extensible way.

Example using OCP:

Here we will write a common contract using the interface.

public interface IBank
{
void SendMoney(string accountNumber, decimal amount);
}
class BankA : IBank
{
public void SendMoney(string accountNumber, decimal amount)
{
// Send money using Bank A
Console.WriteLine($"Sending {amount} to {accountNumber}");
}
}
class BankB : IBank
{
public void SendMoney(string accountNumber, decimal amount)
{
// Send money using Bank B
Console.WriteLine($"Sending {amount} to {accountNumber}");
}
}
class BankC : IBank
{
public void SendMoney(string accountNumber, decimal amount)
{
// Send money using Bank C
Console.WriteLine($"Sending {amount} to {accountNumber}");
}
}
public class MoneySender
{
private readonly IBank _bank;

public MoneySender(IBank bank)
{
_bank = bank;
}

public void SendMoney(string accountNumber, decimal amount)
{
_bank.SendMoney(accountNumber, amount);
}
}

Here, thanks to the interface, it will be enough to tell us which class that implements the interface will be given. If another bank comes one day, we will open a special class for that bank and extend the code. This is why extending is very important.

MoneySender moneySender = new(new BankA());
moneySender.SendMoney("123456789", 1000);


MoneySender moneySender = new(new BankB());
moneySender.SendMoney("123456789", 1000);

As you can read from the code, if there is a bank change in the future, we only need to new that bank. But we don’t need to make any changes to the function that sends the actual money. This means that we follow the Open Closed principle.

What are its advantages?

  1. Flexibility and Extensibility: Provides the ability to make changes to the system by simply adding new code, rather than modifying existing code to add new features.
  2. Ease of Maintenance: Not changing existing code simplifies troubleshooting and maintenance. Reduces the risk of unexpected impacts to existing code.
  3. Code Reusability: Increases code reusability by using abstraction and using interfaces. You can easily substitute different classes that implement the same interface.

This will break the resistance of the code to change according to new requirements, and isolate the developer from the costs associated with these change processes.

Thank you for reading :)

--

--

Responses (1)