In this article we are going to discuss Open/Closed Principle in C#. There are many blogs, articles are available on the internet regarding Open/Closed Principle but in this particular article I will try to explain to you with as much as simple.
Open/Closed Principle
The Open/Closed Principle (OCP) is one of the SOLID principles of object-oriented design. It states that software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means you should be able to add new functionality to a class without changing its existing code, which helps maintain stability and reduces the risk of introducing bugs when requirements change.
Here’s a detailed explanation along with an example of violating and adhering to the OCP in C#:
Violating the Open/Closed Principle
Imagine you have a class that calculates the area of different shapes. Initially, it only supports rectangles:
public class AreaCalculator
{
public double CalculateArea(Rectangle rectangle)
{
return rectangle.Width * rectangle.Height;
}
}
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
}
Now, you need to extend the functionality to support circles. You might be tempted to modify the AreaCalculator class.
public class AreaCalculator
{
public double CalculateArea(Rectangle rectangle)
{
return rectangle.Width * rectangle.Height;
}
public double CalculateArea(Circle circle)
{
return Math.PI * circle.Radius * circle.Radius;
}
}
public class Circle
{
public double Radius { get; set; }
}
This violates the OCP because you had to modify the AreaCalculator class to add support for circles. Every time you need to support a new shape, you’ll have to modify this class, which is not scalable and makes the code fragile.
Adhering to the Open/Closed Principle
To adhere to the OCP, you should design your classes in a way that new functionality can be added without modifying existing code. One way to achieve this is by using interfaces or abstract classes.
First, define a common interface for shapes:
Using interfaces or abstract classes to extend functionality without changing
existing code (e.g., IShape interface and polymorphism).
By following the OCP, you make your code more modular, extensible, and easier to
maintain.
using System;
public interface IShape
{
double CalculateArea();
}
public class Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public double CalculateArea()
{
return Width * Height;
}
}
public class Circle : IShape
{
public double Radius { get; set; }
public double CalculateArea()
{
return Math.PI * Radius * Radius;
}
}
public class AreaCalculator
{
public double CalculateArea(IShape shape)
{
return shape.CalculateArea();
}
}
public class Program
{
public static void Main()
{
// Create instances of Rectangle and Circle
Rectangle rectangle = new Rectangle { Width = 5, Height = 10 };
Circle circle = new Circle { Radius = 7 };
// Create an instance of AreaCalculator
AreaCalculator areaCalculator = new AreaCalculator();
// Calculate the area of the rectangle
double rectangleArea = areaCalculator.CalculateArea(rectangle);
Console.WriteLine("The area of the rectangle is: " + rectangleArea);
// Calculate the area of the circle
double circleArea = areaCalculator.CalculateArea(circle);
Console.WriteLine("The area of the circle is: " + circleArea);
}
}
Output
With this design, you can add new shapes without modifying the AreaCalculator class.
public class Triangle : IShape
{
public double Base { get; set; }
public double Height { get; set; }
public double CalculateArea()
{
return 0.5 * Base * Height;
}
}