Click here to Skip to main content
Click here to Skip to main content

Open Closed Principle

, 6 Jun 2006
Rate this:
Please Sign up or sign in to vote.
Object Oriented Design

Introduction

One thing is certain in all software development, all software changes during its life cycle. So, it is imperative that developers design software that is stable (i.e. does not change) in the face of ever changing functional requirements. To aid in this development, Robert Martin gave us the open-closed principle, which states:

SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION [Martin].

Software modules that satisfy the open-closed principle have two huge benefits. First, they are "open for extension". (The behavior of the modules can be altered to satisfy the changing requirements.) Second, these modules are "closed for modification". (The modules, themselves are not allowed to change.) In this article, we will describe the open closed principle via a simple example.

Background

Consider the following example. We have an application that must be able to manage different kind of shapes (i.e. circles, squares, polygon, etc.) and draw them on a standard GUI. Using techniques that do not conform to the open-closed principle, we might solve this problem as shown below:

class Shape
{
     private Point _center;

    #region Center Get / Set
};

class Circle : Shape 
{
    private int _radius;

    #region Radius Get / Set
}

class Square : Shape 
{
    private int _side;

    #region Side Get / Set
}

These first classes encapsulate the shapes' data structure. The following manager performs several operations on the shapes such as draw and serialize.

class DrawManager
 {
        private List<Shape> _shapeList;
        
        public DrawManager()

        public void add(Shape s)
        
        // Serialize all registered shapes
        // This method is not conformed to the Open Closed Principle
        public void serializeShape(string fileName)
        
        // Draw all registered shapes
        public void drawShapes()
        { 
            // This method is not conformed to the Open Closed Principle
            foreach(Shape s in _shapeList)
            {
                if (s is Circle)
                {
                    _drawCirle((s as Circle));
                }
                else if (s is Square)
                {
                    _drawSquare((s as Square));
                }
            }
        }
        // The concrete implementations of these methods are not 
        // important in this discussion
        private void _drawCirle(Circle c)
        private void _drawSquare(Square sq)
        private void _serializeCirle(Circle c)
        private void _serializeSquare(Square sq)
  };

The method drawShapes walks a list of Shape, examining the Shape type and then calling the appropriate private draw method (either _drawCircle or _drawSquare). The problem with the above design is that it violates the Open Closed Principle because it cannot be closed against new kinds of shapes. If I wanted to extend this function to be able to draw a list of shapes that included triangles, I would have to modify the function. In fact, I would have to modify the function for any new type of shape that I needed.

Of course this program is only a simple example. In real life, the switch statement in the drawShapes function would be repeated over and over again in various functions all over the application; each one doing something a little different (for example, the method serializeShape has the same problem). Adding a new shape to such an application means hunting for every place that such switch statements (or if/else chains) exist, and adding the new shape to each. Moreover, it is very unlikely that all the switch statements and if/else chains would be as nicely structured as the one in drawShapes. It is much more likely that the predicates of the if statements would be combined with logical operators, or that the case clauses of the switch statements would be combined so as to “simplify” the local decision making. Thus the problem of finding and understanding all the places where the new shape needs to be added can be non-trivial.

Solution

The following code is a possible solution to the shapes problem that it conforms to the open-closed principle. In this case, the abstract Shape class defines a single pure-virtual function called Draw. Both Circle and Square override the function in a different way.

abstract class Shape
    {
        private Point _center;

        // Define an abstract way to draw a shape
        public abstract void Draw();
    };

    class Circle : Shape 
    {
        private int _radius;

        // Override the abstract method to draw a circle
        // The concrete implementation is not important in this discussion
        public override void Draw()
    }

    class Square : Shape 
    {
        private int _side;

        // Override the abstract method to draw a square
        // The concrete implementation is not important in this discussion
        public override void Draw()
    }

    class DrawManager
    {
        //......
        //......
        
        public void drawShapes()
        {
            foreach (Shape s in _shapeList)
                s.Draw();
        }
        
        //......
        //......
    }  

Note that if we want to extend the behavior of the DrawShapes function to draw a new kind of shape, now, all we need to do is add a new derivative of the Shape class. The DrawShapes function does not need to change. Thus DrawShapes conforms to the open-closed principle. Its behavior can be extended without modifying it.

In the real world, the Shape class would have many more methods. Yet adding a new shape to the application is still quite simple since all that is required is to create the new derivative and implement all its functions. There is no need to hunt through all of the application looking for places that require changes. Since programs that conform to the open-closed principle are changed by adding new code, rather than by changing existing code, they do not experience the cascade of changes exhibited by non-conforming programs.

Points of Interest

As you could realize, the Open Closed Principle is referring to using Abstract Classes and their Concrete SubClasses to extend behavior. This essentially means using something like the Template Method Pattern or Strategy Pattern to delegate either part or all of an algorithm in a Concrete SubClass [Gof]. A Template Method is a Method in an (abstract) base class which calls one or more HookMethods to fulfill parts of its tasks. You can easily extend or change the behavior of the abstract base class by creating new subclasses that implement a new version of the Hook method. This fulfills the requirements of the Open-Closed Principle.

Conclusion

It should be clear that no significant program can be 100% closed. For example, consider what would happen to the DrawShapes function if we decided that all Circles should be drawn before any Squares. The DrawShapes function is not closed against a change like this. In general, no matter how “closed” a module is, there will always be some kind of change against which it is not closed. Since closure cannot be complete, it must be strategic. That is, the designer must choose the kinds of changes against which to close his design. This takes a certain amount of prescience derived from experience. The experienced designer knows the users and the industry well enough to judge the probability of different kinds of changes. He then makes sure that the open-closed principle is invoked for the most probable changes.

References

History

  • June 2006: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

svigano
Team Leader
Italy Italy
Simone Viganò is from Milano, Italy. He has been in the programming career since 1999, when he was 20 years old.
He has filled a variety of roles ranging from Junior Developer to Senior Software Engineer and Consultant.
For the last 5 years he has worked extensively on Artificial Vision System programming VC++/MFC, ATL/COM and DirectShow.
Simone is also experienced with C#, VB.net and Java (J2EE - J2ME).
Actually He is working as a Team Leader for a company involved in the building automation systems (HVAC-BAS).
He has his Degree in Computer Science from Milano-Bicocca University, Italy.
He has a Master in ICT (Information Technology and Comunication) Management
from Milano-Bicocca University, Italy.
Simone is just a passionate cool-dude about Software Enginee.

Comments and Discussions

 
GeneralNice Article Pinmemberuttam198-May-09 1:50 
GeneralRe: Nice Article Pinmembersvigano8-May-09 4:43 
QuestionWHY CONFUSE PEOPLE???? PinmemberMr.Programer8-Jun-06 5:07 
QuestionWhy confuse people ? PinmemberMaximilien6-Jun-06 6:09 
AnswerRe: Why confuse people ? Pinmemberleppie6-Jun-06 6:48 
AnswerRe: Why confuse people ? Pinmembersvigano6-Jun-06 12:52 
Hi Maximilien,
 
You're right, in this article you could easly find classic OO concept.
By chance I found Bertrand Meyer's article...I'd liked his definitions and his
point of view about software development and I thought it should be nice to share it with the codeproject comunity.
Personally I don't think this kind of terminology could confuse people....but
I accept your criticism. Smile | :)

GeneralRe: Why confuse people ? PinmemberKevin McFarlane8-Jun-06 6:18 
AnswerYou are confused PinmemberSilentSilent7-Jun-06 0:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 6 Jun 2006
Article Copyright 2006 by svigano
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid