This is firstly described by Bertrand Mayer as “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”.

This is basically for designing a code as can be acted more robust when you need to add a new feature.

It makes the code more strong by making it Open for Extension and Closed for modification.

How to make a class open for extension and closed for modification at the same time?

You can make a class closed for modification by open it for extension.

So, in the Bad OCP version, the implementation logic for each sub class is included in the centralized control hub. But in the Good OCP version the implementation is delegate to each sub classes. So no need to change the centralized code each time you need to add a new feature.

Bad OCP Design

AreaCalculator .java

package ocp.bad;

import ocp.bad.shapes.Circle;
import ocp.bad.shapes.Rectangle;
import ocp.bad.shapes.Shape;

public class AreaCalculator {

public double caclculateArea(Shape[] shapes){
double totalArea = 0d;

for (Shape shape : shapes) {

double area = 0d;

if(shape instanceof Rectangle){
area = ((Rectangle) shape).getHeight() * ((Rectangle) shape).getWidth();
System.out.println("Area of the rectangle : "+area);
}else if (shape instanceof Circle){
area = ((Circle) shape).getRadius() * ((Circle) shape).getRadius() * Math.PI;
System.out.println("Area of the circle : "+area);
}
// When more shapes added more else-if need to be added s and changes of the code here.

totalArea += area;
}
System.out.println("Returning totalArea : "+totalArea);
return totalArea;
}

}

Shape.java

package ocp.bad.shapes;

public class Shape {}

Rectangle.java

package ocp.bad.shapes;

public class Rectangle extends Shape {

	public Rectangle( double width, double height) {
		this.width 	= width;
		this.height = height;
	}

	public double getWidth() {
		return width;
	}

	public double getHeight() {
		return height;

	}

	private double width = 0d;
	private double height = 0d;

}

Circle.java

package ocp.bad.shapes;

public class Circle extends Shape {

	public Circle(double radius) {
		this.radius = radius;
	}

	public double getRadius() {
		return radius;
	}

	private double radius = 0d;

}

Good OCP Design

Here, the implementation logic (what it differs has been delegated to its own sub classes). So, no need to change the centralized code each time you need to add a new feature.

AreaCalculator .java

package ocp.good;

import ocp.good.shapes.Shape;

public class AreaCalculator {

	public double caclculateArea(Shape[] shapes){
		double totalArea = 0d;

		for (Shape shape : shapes) {

			totalArea += shape.calculateArea();
			// When more shapes added no need to change here. Implementation has deligate to the new objects through abstraction
		}
		System.out.println("Returning totalArea : "+totalArea);
		return totalArea;
	}

}

Shape.java

package ocp.good.shapes;

public abstract class Shape {
	public abstract double calculateArea();
}

Rectangle.java

package ocp.good.shapes;

public class Rectangle extends Shape {

	public Rectangle( double width, double height) {
		this.width 	= width;
		this.height = height;
	}

	@Override
	public double calculateArea() {
		return width * height;
	}

	private double width = 0d;
	private double height = 0d;

}

Circle.java

package ocp.good.shapes;

public class Circle extends Shape {

	public Circle(double radius) {
		this.radius = radius;
	}

	@Override
	public double calculateArea() {
		return radius * radius * Math.PI;
	}

	private double radius = 0d;

}

References :

Advertisements