Open-Closed Principle (OCP)

Intent

Software entities such as classes, modules and functions should be open for extension but closed for modification.

Description

A banking application represents different types of accounts through the following class.

Account.cs

enum AccountType {SAVINGS, FIXEDDEPOSIT, SALARY};

class AccountInfo

{

string name;

string address;

string accountNo;

string baseBranch;

}

class Account

{

//implementation defined elsewhere

AccountInfo accInfo;

private AccountType type;

private double balance;

public Account(AccountType type, double balance)

{

this.type = type;

this.balance = balance;

}

public void withdraw(double amount)

{

balance -= amount;

}

public void deposit(double amount)

{

balance += amount;

}

void calculateInterest()

{

switch(type)

{

case AccountType.SAVINGS:

//implementation

break;

case AccountType.FIXEDDEPOSIT:

//implementation

break;

case AccountType.SALARY:

//implementation

break;

}

}

}

There may be other modules that may be depending on the Account class for functionality. If the bank decides to add more types of accounts, the Account class will have to be modified. This change may introduce bugs and cause the class to fail in different ways. The enumeration will also change. All the other modules that depend on Account class will also be affected and may require a recompilation, retesting, redeployment etc…

Refactored Solution

The open-Closed Principle suggests writing the code in such a way that:

  • The modules are open for extension. Their behavior can be changed by adding new code.
  • The existing code is closed for modification and we rarely need to modify existing code to change the behavior of the module.

Object oriented programming provides us with tools to implement the Open-Closed Principle. One way is to use the code through abstractions and polymorphism. Applying this to the Account class, we would get a hierarchy of account classes where each account class will take cake of its own functionality. The enumeration will not be required.

Account.cs

class AccountInfo

{

string name;

string address;

string accountNo;

string baseBranch;

}

abstract class Account

{

//implementation defined elsewhere

AccountInfo accInfo;

private double balance;

public Account(double balance)

{

this.balance = balance;

}

public void withdraw(double amount)

{

balance -= amount;

}

public void deposit(double amount)

{

balance += amount;

}

public abstract void calculateInterest ();

}

Savings.cs

class Savings : Account

{

public Savings(double balance)

: base(balance)

{

}

public override void calculateInterest()

{

//implementation

}

}

FixedDeposit.cs

class FixedDeposit : Account

{

public FixedDeposit(double balance)

: base(balance)

{

}

public override void calculateInterest()

{

//implementation

}

}

Salary.cs

class Salary : Account

{

public Salary(double balance)

: base(balance)

{

}

public override void calculateInterest()

{

//implementation

}

}

The modules that need to use the account classes will depend on the abstract class Account and use the sub-classes through its reference or pointer. If more account classes are added or existing ones change, it will not have any impact on the surrounding code. Another advantage is that the common code is factored out in the base class and avoids duplication. You can see Liskov Substitution Principle (LSP) as the next post. Stay tuned with us.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s