SOLID Principles

Implementing OCP in C#

To implement the Open/Closed Principle, you can use various techniques such as abstract classes, interfaces, and inheritance. Here are a few examples to illustrate how you can apply OCP in C#.

Example 1: Using Inheritance and Polymorphism
Consider a scenario where we have a base Shape class and several derived classes representing specific shapes.

Violating OCP

public class Shape
{
    public string Type { get; set; }
}

public class AreaCalculator
{
    public double CalculateArea(Shape shape)
    {
        if (shape.Type == "Circle")
        {
            Circle circle = (Circle)shape;
            return Math.PI * circle.Radius * circle.Radius;
        }
        else if (shape.Type == "Rectangle")
        {
            Rectangle rectangle = (Rectangle)shape;
            return rectangle.Width * rectangle.Height;
        }
        // More shape types...

        throw new ArgumentException("Unknown shape type");
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
}

In this design, the CalculateArea method in the AreaCalculator class needs to be modified every time a new shape is added, which violates the Open/Closed Principle.

Adhering to OCP

public abstract class Shape
{
    public abstract double CalculateArea();
}

public class Circle : Shape
{
    public double Radius { get; set; }

    public Circle(double radius)
    {
        Radius = radius;
    }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public Rectangle(double width, double height)
    {
        Width = width;
        Height = height;
    }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class AreaCalculator
{
    public double CalculateArea(Shape shape)
    {
        return shape.CalculateArea();
    }
}

In this refactored design, the Shape class is an abstract base class with a CalculateArea method that each derived class overrides. The AreaCalculator class no longer needs to be modified when a new shape is added, adhering to the Open/Closed Principle.