Wednesday, July 16, 2008

The Open-Close Principle (OCP)

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

OCP is essentially equivalent to the Protected Variation pattern: Identify points of predicted variation and create a stable interface around them.

The Open Close Principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.

Example
Bellow is an example which violates the Open Close Principle. It implements a graphic editor which handles the drawing of different shapes. It's obviously that it does not follow the Open Close Principle since the GraphicEditor class has to be modified for every new shape class that has to be added. There are several disadvantages:
  • for each new shape added the unit testing of the GraphicEditor should be redone.
  • when a new type of shape is added the time for adding it will be high since the developer who add it should understand the logic of the GraphicEditor.
  • adding a new shape might affect the existing functionality in an undesired way, even if the new shape works perfectly


// Open-Close Principle - Bad example
class GraphicEditor {
public void drawShape(Shape s) {
if (s.m_type == 1)
drawRectangle(s);
else if (s.m_type == 2)
drawCircle(s);
}

public void drawCircle(Circle r) {....}

public void drawRectangle(Rectangle r) {....}
}

class Shape {
int m_type;
}

class Rectangle extends Shape {
Rectangle() {
super.m_type = 1;
}
}

class Circle extends Shape {
Circle() {
super.m_type = 2;
}
}


Bellow is a example which supports the Open Close Principle. In the new design we use abstract draw() method in GraphicEditor for drawing objects, while moving the implementation in the concrete shape objects. Using the Open Close Principle the problems from the previous design are avoided, because GraphicEditor is not changed when a new shape class is added:
  • no unit testing required.
  • no need to understand the source code from GraphicEditor.
  • since the drawing code is moved to the concrete shape classes, it's a reduced risk to affect old functionality when new functionality is added.


//Open-Close Principle - Good example
class GraphicEditor {
public void drawShape(Shape s) {
s.draw();
}
}

class Shape {
abstract void draw();
}

class Rectangle extends Shape {
public void draw() {
// draw the rectangle
}
}


Exempt from here.

No comments:

Post a Comment