Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Software Architecture Cheat Blog 3: Open Closed Principle

3 Oct 2012CPOL2 min read 6.6K  
Open Closed Principle (OCP) states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modifications.

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.

C#
public enum AccountTYpe
{
    Savings,
    Checking,
    MoneyMarket 
}

public class Accounts
{
    private AccountTYpe accountType { get; set; }

    public Decimal CalculateInterest()
    {
        Decimal interest = 0;
        if (accountType == AccountTYpe.Savings)
        {
            //consider business rules and calculate interest of savings account
            interest = 2.50m;
        }
        else if (accountType == AccountTYpe.Checking)
        {
            //consider business rules and calculate interest of checking account
            interest = 3.50m;
        }
        else
        {
            //consider business rules and calculate interest of money market account
            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:

C#
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)
        {
            //consider business rules and calculate interest of savings account
            interest = 2.50m;
        }
        else if (accountType == AccountTYpe.Checking)
        {
            //consider business rules and calculate interest of checking account
            interest = 3.50m;
        }
        else if (accountType == AccountTYpe.CertificatesOfDeposit)
        {
            //consider business rules and calculate interest of certificates of deposit account
            interest = 6.35m;
        }
        else
        {
            //consider business rules and calculate interest of money market account
            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.

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)