Software Development

SOLID – Open Closed Principle

Open Closed Principle (OCP) states that,

Software entities (Classes, modules, functions) should be OPEN for EXTENSION, CLOSED for MODIFICATION.

Lets try to reflect on the above statement- software entities once written shouldn’t be modified to add new functionality, instead one has to extend the same to add new functionality.

In other words you don’t touch the existing modules thereby not disturbing the existing functionality, instead you extend the modules to implement the new requirement. So your code is less rigid and fragile and also extensible.

OCP term was coined by Bertnard Meyer.

How can we confirm to OCP principle?

Its simple – Allow the modules (classes) to depend on the abstractions, there by new features can be added by creating new extensions of these abstractions.

Let me try to explain with an example:

Suppose you are writing a module to approve personal loans and before doing that you want to validate the personal information, code wise we can depict the situation as:

public class LoanApprovalHandler
{
  public void approveLoan(PersonalValidator validator)
  {
    if ( validator.isValid())
    {
      //Process the loan.
    }
  }
}
public class PersonalLoanValidator
{
  public boolean isValid()
  {
    //Validation logic
  }
}

So far so good. As you all know the requirements are never the same and now its required to approve vehicle loans, consumer goods loans and what not. So one approach to solve this requirement is to:

public class LoanApprovalHandler
{
  public void approvePersonalLoan (PersonalLoanValidator validator)
  {
    if ( validator.isValid())
    {
      //Process the loan.
    }
  }
  public void approveVehicleLoan (VehicleLoanValidator validator )
  {
    if ( validator.isValid())
    {
      //Process the loan.
    }
  }
  // Method for approving other loans.
}
public class PersonalLoanValidator
{
  public boolean isValid()
  {
    //Validation logic
  }
}
public class VehicleLoanValidator
{
  public boolean isValid()
  {
    //Validation logic
  }
}

We have edited the existing class to accomodate the new requirements- in the process we ended up changing the name of the existing method and also adding new methods for different types of loan approval. This clearly violates the OCP. Lets try to implement the requirement in a different way:

/**
 * Abstract Validator class
 * Extended to add different
 * validators for different loan type
 */
public abstract class Validator
{
  public boolean isValid();
}
/**
 * Personal loan validator
 */
public class PersonalLoanValidator
  extends Validator
{
  public boolean isValid()
  {
    //Validation logic.
  }
}
/*
 * Similarly any new type of validation can
 * be accommodated by creating a new subclass
 * of Validator
 */

Now using the above validators we can write a LoanApprovalHandler to use the Validator abstraction.

public class LoanApprovalHandler
{
  public void approveLoan(Validator validator)
  {
    if ( validator.isValid())
    {
      //Process the loan.
    }
  }
}

So to accommodate any type of loan validators we would just have create a subclass of Validator and then pass it to the approveLoan method. That way the class is CLOSED for modification but OPEN for extension.

Another example:

I was thinking of another hypothetical situation where the use of OCP principle can be of use. The situation is some thing like: “We maintain a list of students with their marks, unique identification(uid) and also name. Then we provide an option to get the percentage in the form of uid-percentage name value pairs.”

class Student
{
  String name;
  double percentage;
  int uid;
  public Student(String name, double percentage, int uid)
  {
    this.name = name;
    this.percentage = percentage;
    this.uid = uid;
  }
}

We collect the student list into a generic class:

class StudentBatch {
  private List<Student> studentList;
  public StudentBatch() {
    studentList = new ArrayList<Student>();
  }
  public void getSutdentMarkMap(Hashtable<Integer, Double> studentMarkMap) {
    if (studentMarkMap == null) {
      //Error
    } else {
      for (Student student : studentList) {
        studentMarkMap.put(student.uid, student.percentage);
      }
    }
  }
  /**
   * @param studentList the studentList to set
   */
  public void setStudentList(List<Student> studentList) {
    this.studentList = studentList;
  }
}

Suppose we need to maintain the order of elements in the Map by their insertion order, so we would have to write a new method to get the map in the insertion order and for that we would be using LinkedHashMap. Instead if the method- getStudentMarkMap() was dependent on the Map interface and not the Hashtable concrete implementation, we could have avoided changing the StudentBatch class and instead pass in an instance of LinkedHashMap.

public void getSutdentMarkMap(Map<Integer, Double> studentMarkMap) {
    if (studentMarkMap == null) {
      //Error
    } else {
      for (Student student : studentList) {
        studentMarkMap.put(student.uid, student.percentage);
      }
    }
  }

PS: I know that Hashtable is an obsolete collection and not encouraged to be use. But I thought this would make another useful example for OCP principle.

Some ways to keep your code closer to confirming OCP:

Making all member variables private so that the other parts of the code access them via the methods (getters) and not directly.
Avoiding typecasts at runtime- This makes the code fragile and dependent on the classes under consideration, which means any new class might require editing the method to accommodate the cast for the new class.

Really good article written by Robert Martin on OCP.

Reference: SOLID- Open Closed Principle from our JCG partner Mohamed Sanaulla at the “Experiences Unlimited” blog.

Related Articles :
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Wasan Ngamphat
Wasan Ngamphat
7 years ago

I agree with you about refactoring PersonalLoanValidator and VehicleLoanValidator to Validator but disagree in method “approveLoan” should not have an argument is Validator.

My perspective, method “approveLoan” should approve argument as send to itself such as credit limits, Loan limits or personal loan request etc.

Back to top button