Software Design - Open Close Principle

We will start with what Introduction and then explain the principle with an example.

1. Introduction

2. Example

We want to draw different kind of images. For this, We wrote a generic class ImageEditer which can draw shapes. See the below code snippet.

public class ImageEditor {
public void drawShape (Shape s) {
final int shapeType = s.getType();
//Based on shape type draw shapes code
if (shapeType == Shape.TYPE_RECTANGLE) {
drawRectangle(s);
}
else if (shapeType == Shape.TYPE_SQUARE) {
drawSquare(s);
}
}

private void drawRectangle(Shape s) {
// Logic to draw Rectangle
}

private void drawSquare(Shape s) {
// logic to draw Square
}
}


abstract class Shape {
public static final int TYPE_RECTANGLE = 1;
public static final int TYPE_SQUARE = 2;

private int type;

Shape (int type) {

}

public int getType() {
return type;
}
}

//Rectangle
class Rectangle extends Shape {
Rectangle () {
super(TYPE_RECTANGLE);
}
}

//Square
class Square extends Shape {
Square () {
super(TYPE_SQUARE);
}
}

We have Shape as abstract class and then its concrete implementations like Rectangle, Square. And, we have ImageEditor class who have only exposing drawShape() to draw shape of any type and it is hiding method to draw specific image like Rectangle, Square etc. Atleast, we are using abstraction, encapsulation, hiding etc. features of OOPs(pun intended).

3. Problem with above structure

In case we are required to add new shape say Polygon then what?. Will our ImageEditor be able to draw it? Answer is No.

We need to change ImageEditor class to support this behavior. It means we need to modify it??? If we modify it then we need to unit test it. One change can raise some other issue in class.

So, how we can ensure to close ImageEditor for modifications?

4. A better approach

Let's follow Open Close principle in ImageEditor class along with Single Responsibility Principle.

public class ImageEditor {
public void drawShape (Shape s) {
s.draw();
}
// other methods related to editing image goes here
}

abstract class Shape {
private String name;

Shape (String name) {
this.name = name;
}

public String getName() {
return name;
}

abstract void draw();
}

//Rectangle
class Rectangle extends Shape {
Rectangle () {
super("Rectangle");
}

@Override
public void draw() {
//logic to draw RECTANGLE
}
}

//Square
class Square extends Shape {
Square () {
super("Square");
}

@Override
public void draw() {
//logic to draw SQUARE
}
}

We declared the responsibility to draw in Shape but also make it out abstract so that every concrete class should define how to draw itself.

In the ImageEditor class, the drawShape() delegate the call to draw to Shape class. Now, with this change we can draw any kind of shape and in future if it has to draw new shape then we don't have to modify it.



Tags: SOLID principles, Open Close Principle, Object Oriented software construction, Software Design

← Back home