Open close principle
- Bertrand Meyer coined the term open close principle in his 1988 book Object Oriented Software Construction.
- Software entities like classes, modules and functions should be "open for extension but closed for modifications".
- It is a generic principle. You can consider it when writing your classes to make sure that when you need to extend their behaviour you don't have to change the class but to extend it.
- When referring to the classes Open Close principle can be ensured by the use of Abstract classes and/ or Interfaces and concrete classes implementing their behaviour. This will enforce having concrete classes implementing Abstract classes/ Interfaces instead of changing them.
- Some particular cases where this principle is used are Template Design Pattern, Strategy design pattern.
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.
package javawithgaurav.openclose; /** * * @author Gaurav Rai Mazra * <a href="www.javawithgaurav.blogspot.in">Click here to view more</a> */ //Abstract class different type of Shape 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); } }
package javawithgaurav.openclose; /** * * @author Gaurav Rai Mazra * <a href="www.javawithgaurav.blogspot.in">Click here to view more</a> */ 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 } }
By looking into above code snippet, we see no problem. 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).
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?
Good approachWe will change it according to OCP and also SRP. Let's do it in the code snippet below.
package javawithgaurav.openclose; /** * * @author Gaurav Rai Mazra * <a href="www.javawithgaurav.blogspot.in">Click here to view more</a> */ //Abstract class different type of Shape 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 } }
package javawithgaurav.openclose; /** * * @author Gaurav Rai Mazra * <a href="www.javawithgaurav.blogspot.in">Click here to view more</a> */ public class ImageEditor { public void drawShape (Shape s) { s.draw(); } // other methods related to editing image goes here }
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
. 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.