Skip to main content

Open Closed Principle

 

Open Closed Principle

We will be discussing the Open-Closed Principle also known as OCP, as one of the SOLID principles of object-oriented programming and how to implement it when designing our software.

This principle said that should be open for extension but closed for modification. We should write a code that does not require modification every time a customer changes its request.

Example

Let us define a class that contains salary calculations.

Let us imagine that we have a task where we need to calculate the total cost of all the developer salaries in a single company.

To get started, we are going to create the model class first,

public class EmployeeReport {
    public int Id {
        get;
        set;
    }
    public string Name {
        get;
        set;
    }
    public string Level {
        get;
        set;
    }
    public int WorkingHours {
        get;
        set;
    }
    public double HourlyRate {
        get;
        set;
    }
}
C#

We can design the salary calculation method in another class.

public class SalaryCalculator {
    private readonly IEnumerable < EmployeeReport > _employeeReports;
    public SalaryCalculator(List < EmployeeReport > employeeReports) {
        _employeeReports = employeeReports;
    }
    public double CalculateTotalSalaries() {
        double totalSalaries = 0 D;
        foreach(var devReport in _employeeReports) {
            totalSalaries += devReport.HourlyRate * devReport.WorkingHours;
        }
        return totalSalaries;
    }
}
C#

Then call this method on the main program.

class OCP {
    public OCP() {
        Run();
    }
    public void Run() {
        var devReports = new List < EmployeeReport > {
            new EmployeeReport {
                Id = 1,
                    Name = "Amit Kumar",
                    Level = "Senior developer",
                    HourlyRate = 30.5,
                    WorkingHours = 160
            },
            new EmployeeReport {
                Id = 2,
                    Name = "Nirmal Dayal",
                    Level = "Junior developer",
                    HourlyRate = 20,
                    WorkingHours = 150
            },
            new EmployeeReport {
                Id = 3,
                    Name = "Sheeba John",
                    Level = "Senior developer",
                    HourlyRate = 30.5,
                    WorkingHours = 180
            }
        };
        var calculator = new SalaryCalculator(devReports);
        Console.WriteLine($ "Sum of all the developer salaries is {calculator.CalculateTotalSalaries()} Rupees");
        Console.ReadLine();
    }
}
C#

So, all this solution is working great, but now our team leader comes to our desk and says that we need a different calculation for the senior and junior developers. The senior developers should have a bonus of 20% on a salary.

Of course, to satisfy this requirement, we are going to modify our CalculateTotalSalaries method like this,

public double CalculateTotalSalaries() {
    double totalSalaries = 0 D;
    foreach(var empReport in _ employeeReports) {
        if (empReport.Level == "Senior developer") {
            totalSalaries += empReport.HourRate * empReport.WorkingHours * 1.2;
        } else {
            totalSalaries += empReport.HourRate * empReport.WorkingHours;
        }
    }
    return totalSalaries;
}
C#

Mainly, because we had to modify our existing class behavior which worked perfectly. Another thing is that if our team leader comes again and asks us to modify the calculation for the junior devs as well, we would have to change our class again. This is totally against what OCP stands for.

Again, Modify the code as per OCP Principle,

public abstract class BaseSalaryCalculator {
    protected EmployeeReport EmployeeReport {
        get;
        private set;
    }
    public BaseSalaryCalculator(EmployeeReport employeeReport) {
        EmployeeReport = employeeReport;
    }
    public abstract double CalculateSalary();
}
C#

Define another class for SeniorDevSalaryCalculator.cs,

public class SeniorDevSalaryCalculator: BaseSalaryCalculator {
    public SeniorDevSalaryCalculator(EmployeeReport report): base(report) {}
    public override double CalculateSalary() => EmployeeReport.HourlyRate * EmployeeReport.WorkingHours * 1.2;
}
C#

Conclusion

Even though the name of the principle is self-explanatory, we can see how easy it is to implement incorrectly. Make sure to distinguish the logic of every class -- it does not need to change the current class if you have more categories, but you must extend the abstract class and perform the logic and implementation as per requirement comes.

Comments

Popular posts from this blog

How to find the count to convert a pyramid into a square using C#.net

Introduction   Let’s develop a simple C# console application to find the count of convert a pyramid into a square. Getting Started In ASP.NET 5 we can create console applications. To create a new console application, we first open Visual Studio 2015. Create it using File-> New-> Project. Now we will select the ASP.NET 5 Console Application to create the console application, click on the OK button. Include the following references in the application: using  System;   using  System.Collections.Generic;   using  System.Linq;  In the main method, I have created 2 methods 1.PrintPyramid – To print the triangle in given input. 2.ConvertPyramidToSquare = Convert triangle into square. Please refer the code snippet below: static   void  Main( string [] args)   {   try    {   PrintPyramid();   ConvertPyram...

Liskov Substitution Principle

Liskov Substitution Principle We will be discussing the Liskov Substitution Principle also known as LSP, as one of the SOLID principles of object-oriented programming and how to implement it when designing our software. This principle said that Subtypes must be substitutable for their base types. In other words, if we substitute a superclass object reference with an object of any of its subclasses, the program should not break. Example Here we design three classes for employees and one abstract class and Implement abstract class on these classes, PermamentEmployee.cs ContractEmployee.cs TemporaryEmployee.cs class LSP { public LSP ( ) { Run ( ) ; } public void Run ( ) { Console . ReadLine ( ) ; } public abstract class Employee { protected string FullName { get ; set ; } protected abstract string CalculateBonus ( ) ; } public class PermamentEmployee : Employee ...