The Open/Closed Principle (OCP) states that:
Software entities should be open for extension but closed for modification.
This means that a class should allow for the addition of new functionalities without changing the existing code, while the behavior of existing classes should not be altered.
Violation of the principle
Imagine having a class that calculates the area of different geometric shapes:
public class AreaCalculator
{
public double CalculateArea(object[] shapes)
{
var area = 0d;
foreach (var shape in shapes)
{
if (shape is Rectangle)
{
var rectangle = (Rectangle)shape;
area += rectangle.Width * rectangle.Height;
}
else if (shape is Circle)
{
var circle = (Circle)shape;
area += Math.PI * Math.Pow(circle.Radius, 2);
}
}
return area;
}
}
This implementation violates the OCP because each time we add a new geometric shape, we have to modify the CalculateArea
method by adding a new conditional if
block.
Application of the principle
To comply with the OCP, we can use inheritance and polymorphism by introducing an IShape
interface with a CalculateArea
method and ensuring that the classes of various shapes implement this interface:
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 * Math.Pow(Radius, 2);
}
}
Now we can rewrite the AreaCalculator
class to use polymorphism to calculate the area of shapes without having to modify the class each time a new geometric shape is added:
public class AreaCalculator
{
public double CalculateArea(IShape[] shapes)
{
var area = 0d;
foreach (var shape in shapes)
{
area += shape.CalculateArea();
}
return area;
}
}
Conclusion
In this article, we have explored the Open/Closed Principle, which guides us in creating classes and modules that are resistant to direct modifications but amenable to extensions. This principle emphasizes the use of abstractions and inheritance to add functionality to classes without altering their original implementation. The result is code that is easier to maintain and more extensible, reducing the impact of changes on pre-existing implementations.
Top comments (0)