Aug 292012
 

The Open Close Principle in Programming says

“Software entities like Classes, Functions, Modules should be open for extension, but closed for modification.”

It encourages programmers to write code in such a way that new functionality can be added without changing the existing code.

i.e If we are writing a class, then we may later, extend the class and create more base classes to it (which will enhance the functionality further), But, we should never be forced to change the code inside the class, just because some more features need to be added. Same goes for functions.

Function violating Open-Close Principle

Let us say we have two shapes

    • Circle
    • Square

and two functions, one of which draws a Circle and other a square.

    // Draws a Circle
    void drawCircle();

    // Draws a Square
    void drawSquare();

And we have a function that takes as parameter, the type of shape to be printed and prints the corresponding shape.

    void printShapes(int type)
    {
        switch(type)
        {
            case 1:
                drawCircle(); break;
            case 2:
                drawSquare(); break;
        }
    }

If we want to add a new shape, say a Triangle. Then we need to write a function that can draw a triangle

    // Draws a Triangle
    void drawTriangle();

Which is ok, because we are adding a new code. But we also need to change the printShapes function (add a new case in the switch statement) this is a problem because it requires a change in the existing code to add enhancement to the module (adding extra shape).

Hence the function printShapes does not follow the Open-Close Principle.

This is a simple piece of code. But in practice, such switch statements would be in many functions across multiple files of code. Adding a new Shape requires a change at all the places. Further, the switch expression may not be a simple type but a complex expression, hence more changes. 

In procedural language like C, it is very difficult to follow the principles which are inherently ment for Object Oriented Programming.

Class violating Open-Close Principle 

Let the two shapes are implemented as classes and functions to draw the corresponding shape is a member of class itself.

Further, Both the classes are inheriting the base class, Shape, as shown on the right side.

The Shape class hold a string which stores the type of the Shape

class Shape
{
    string typeOfShape;
    ...
};

Both the child classes has a draw function which draws the corresponding shape.

class Circle : public shape
{
public:
    Circle(){super.typeOfShape = "circle";}
    void drawCircle();
    ...
};

class Square : public shape
{
public:
    Square(){super.typeOfShape = "square";}
    void drawSquare();
    ...
};

And there is a function that take a shape pointer and calls the draw function of the corresponding class.

void printShape(Shape *s)
{
    if(s.typeOfShape.compare("circle") == 0)
        dynamic_cast<Circle>(*s).drawCircle();
    else
        dynamic_cast<Square>(*s).drawSquare(); 
}

This function has exactly the same problem as function printShapes has in the previous section. The problem is because of bad design of classes.

Redesigning the classes to hold Open-Close principle

Let’s redesign the classes in the previous section (Shape, Circle, Square), so that function  printShape can be made to follow Open-Close Principle.

Shape should be an abstract class with a pure virtual function draw which will be implemented by both the base classes

The three classes above will be changed as shown below:

class Shape
{
    public:
        virtual void draw()=0;
};

class Circle : public Shape
{
    public:
        virtual void draw();
};

class Square : public Shape
{
    public:
        virtual void draw();
};

The Function printShape will not have any RTTI code (like dynamic_cast) now

void printShape(Shape *s)
{
    s->draw();
}

Now, if we want to add a new Shape, say Triangle, then we just need to create a class Triangle that extends Shape and none of the existing code need to be modified including the printShape function.

Following points may be noted while writing the code to follow Open-close Principle:

1. Abstraction is the Key:

The abstract classes define interface and not the implementation. Hence, the module can be closed for modification (If the interface is exhaustively defined), yet the behavior of module can be extended by creating new derivatives of the abstract class.

2. RTTI (Run Time Type Identification) should be avoided:

If you are writing a code, which is taking some action based on the type of class at run time (like using dynamic_cast) , then think twice, because chances are that the code is violating the Open-Close principle.

3. Member variables should be private:

If member variable of a class can be changed from outside the class, then the functions which are dependent on that member variables can be made to behave in a certain way, and hence will not be closed with respect to modification.

4. Global variables are evil:

The logic which applies to public members of a class also applies to global variables.

Programs which follow Open-Close principle are changed by extending the code and not really modifying the code (hence reducing the testing effort to the new code). But it may not be possible to make a code 100% closed to modification for any kind of change request.

By change I mean a new request to extend, not the bugs in the existing code.

But the designer of class/module must be clear that the code is closed against which all types of changes.

What you want to avoid is to have one simple change ripple through the various classes of your application. That makes the system fragile, prone to regression problems, and expensive to extend. To isolate the changes, you want to write classes and methods in such a way that they never need to change once they are written.

  One Response to “Open Close Principle”

Comments (1)
  1. Hahah, My laptop crashed when I was browsing http://www.ritambhara.in last time I was here. And for the past 2 months I have been looking for this weblog, so thankful I located it once again! 😀

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)