Define Principle
Open Closed Principle (OCP) states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modifications.
Violation Example
Let us consider a simple banking module that is responsible for calculating
the interest of accounts with respect to the account type. Say the app owner bank offers to their clients
three types of accounts: savings account, basic checking account, money market deposit account. Each of the account types has
a different interest rate, and the interest
is calculated on other factors such as amount deposited, average balance per month, and so on. Thus based on these business rules we design this class
Accounts
which calculates the interest based on the account type.
public enum AccountTYpe
{
Savings,
Checking,
MoneyMarket
}
public class Accounts
{
private AccountTYpe accountType { get; set; }
public Decimal CalculateInterest()
{
Decimal interest = 0;
if (accountType == AccountTYpe.Savings)
{
interest = 2.50m;
}
else if (accountType == AccountTYpe.Checking)
{
interest = 3.50m;
}
else
{
interest = 5.00m;
}
return interest;
}
}
The above solution works perfectly for our client bank and the app went live and everyone
was happy. A few months later the bank realized other banks are making
money from certificates of deposit accounts, so we should do that too, so let's change our system to accommodate that. Now our revised system looks like this:
public enum AccountTYpe
{
Savings,
Checking,
MoneyMarket,
CertificatesOfDeposit
}
public class Accounts
{
private AccountTYpe accountType { get; set; }
public Decimal CalculateInterest()
{
Decimal interest = 0;
if (accountType == AccountTYpe.Savings)
{
interest = 2.50m;
}
else if (accountType == AccountTYpe.Checking)
{
interest = 3.50m;
}
else if (accountType == AccountTYpe.CertificatesOfDeposit)
{
interest = 6.35m;
}
else
{
interest = 5.00m;
}
return interest;
}
}
Considering the above scenario it is not hard to guess, it will go through
the same process each time the bank wants to launch another account type or change
an existing
account type's business rules. This is where the open closed principle is violated.
Resolution
To solve this we can create a common interface which will be implemented by all classes
that represent the account types. The benefit is future changes can be accommodated better
without modifying the corresponding class.
public interface IAccount
{
Decimal CalculateInterest();
}
public class SavingsAccounts:IAccount
{
public decimal CalculateInterest()
{
return 2.50m;
}
}
public class CheckingAccounts : IAccount
{
public decimal CalculateInterest()
{
return 3.50m;
}
}
public class MoneyMarketAccounts : IAccount
{
public decimal CalculateInterest()
{
return 5.00m;
}
}
Using this approach we can add as many account types as needed, all we need is
to add another class for that account type. Also modifications to the business logic reside
in the respective account type class. Thus the IAccount
interface implements the idea of open for extension but closed for modifications.