In the previous article, we discussed the Single Responsibility Principle. Today we are going to discuss the second SOLID Principle that is the Open Closed Principle. Open Closed Principle states that

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

In first look it might seem like a contradictory statement, how can a class be closed for modification but at the same time open for an extension? To answer this question take a look at the following code

    public class GraphicDesigner
    {
        public void Draw(Shape s)
        {
            if (s.Type == "Rectangle")
                DrawRectangle(s);
            else if (s.Type == "Circle")
                DrawCircle(s);
            else if (s.Type == "Square")
                DrawSquare(s);
        }

        private void DrawSquare(Shape s)
        {
            Console.WriteLine("Square drawn on screen.");
        }

        private void DrawCircle(Shape s)
        {
            Console.WriteLine("Circle drawn on screen.");
        }

        private void DrawRectangle(Shape s)
        {
            Console.WriteLine("Rectangle drawn on screen.");
        }
    }

In the above code you can see that our GraphicDesigner class has three methods DrawCircle, DrawRectangle & DrawSquare. What happens if tomorrow we have to draw a new shape for example triangle? We will need to modify this method and add another check here on the shape type to cater for triangle.
This is violation of Open Closed Principle, now let’s see how we can address this issue?

    public class Shape
    {
        public virtual void Draw()
        {
            Console.WriteLine("Shape drawn on screen.");
        }
    }

    public class Rectangle : Shape
    {
        public override void Draw()
        {
            Console.WriteLine("Rectangle drawn on screen.");
        }
    }

    public class Circle : Shape
    {
        public override void Draw()
        {
            Console.WriteLine("Circle drawn on screen.");
        }
    }

    public class Square : Shape
    {
        public override void Draw()
        {
            Console.WriteLine("Square drawn on screen.");
        }
    }

In the above example we have moved the Draw function to the Shape class and now Rectangle, Square & Circle classes are inheriting from the Shape class. Each of these classes override their own implementation of Draw method that they inherit from the Shape class and here is our GraphicDesigner class

    public class GraphicDesigner
    {
        public void Draw(Shape s)
        {
            s.Draw();
        }
    }

It only takes the Shape object it needs to draw and simply calls it’s Draw method. Shape class is our abstraction and all the GraphicDesigner class needs to know is that it will get a Shape object and it needs to call its Draw method. Whether that Shape is a Rectangle or Triangle is not a concern of the GraphicDesigner class.

Now with our new logic, we can easily introduce new shapes and draw them without modifying the GraphicDesigner class. For example, if we need to introduce the Triangle class, we will simply need to inherit it from the Shape class and our logic inside GraphicDesigner class will not change. Our code now does not violate the Open Closed Principle and is much easier to maintain also.

In the upcoming article, we will take a look at the third principle in SOLID principles which is the Liskov Substitution Principle. Till then Happy Coding!