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 otherwords 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)<br />
  {
    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&lt;Integer, Double&gt; 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.

8 thoughts on “SOLID- Open Closed Principle”

  1. Take this with a pinch of salt. This will make your codebase more complex than it needs to be and it smells of not having good tests and not understanding your code. This contradicts the best practice of refactoring. Why should software suddenly become rigid? Fear. Granted, if the codebase is shared and you don’t know who consumes your code, then this is appropriate if you want backwards compatibility.

    Reply

Leave a Reply

Discover more from Experiences Unlimited

Subscribe now to keep reading and get access to the full archive.

Continue reading