The Open Closed Principle (OCP) is one of the five SOLID principles of object-oriented design. It states that software entities (classes, modules, functions) should be open for extension but closed for modification. This means you should be able to add new functionality without changing existing, tested code.
- Reduces the risk of introducing bugs in existing code
- Makes applications easier to maintain and scale
- Encourages clean, flexible, and reusable design
Implementation
Let us consider an application that calculates the total volume of geometric objects. Initially, the application supports only cuboids.
Example 1: Initial Implementation (Only Cuboids)
Design Overview
- Cuboid class stores dimensions of a cuboid
- Application class calculates total volume
- Main class executes the program
// Class representing a Cuboid
// Stores dimensions: length, breadth, and height
class Cuboid {
public double length;
public double breadth;
public double height;
}
// Application class to calculate total volume
class Application {
// Calculates total volume of all cuboids
public double getTotalVolume(Cuboid[] objects) {
double volumeSum = 0;
// Iterate through each cuboid and calculate volume
for (Cuboid obj : objects) {
volumeSum += obj.length * obj.breadth * obj.height;
}
return volumeSum;
}
}
// Main class to run the program
public class Main {
public static void main(String[] args) {
// Creating first cuboid and setting dimensions
Cuboid c1 = new Cuboid();
c1.length = 5;
c1.breadth = 10;
c1.height = 15;
// Creating second cuboid and setting dimensions
Cuboid c2 = new Cuboid();
c2.length = 2;
c2.breadth = 4;
c2.height = 6;
// Storing cuboids in an array
Cuboid[] cuboids = { c1, c2 };
// Calculating and printing total volume
Application app = new Application();
System.out.println("Total Volume: " + app.getTotalVolume(cuboids));
}
}
Output
Total Volume: 798.0
Problem with This Approach
Now suppose the customer wants to add support for spheres.To do this, the Application class must be modified, which:
- Violates the Open Closed Principle
- Increases risk of future bugs
- Makes the code harder to maintain
Now, lets say the customer wants the application to calculate the volume of a sphere as well. In order to accommodate new type of geometric object, the application also needs to be changed.
Example 2: Violating Open Closed Principle
Here, the Application class is modified to support both cuboids and spheres.
// Class representing a Sphere
class Sphere {
public double radius;
}
// Modified Application class (violates OCP)
class Application {
// Calculates volume for both cuboids and spheres
// Needs modification whenever a new shape is added
public double getTotalVolume(Cuboid[] cuboids, Sphere[] spheres) {
double volumeSum = 0;
// Calculating volume of cuboids
for (Cuboid c : cuboids) {
volumeSum += c.length * c.breadth * c.height;
}
// Calculating volume of spheres
for (Sphere s : spheres) {
volumeSum += (4.0 / 3) * Math.PI * s.radius * s.radius * s.radius;
}
return volumeSum;
}
}
Issue: Every new geometric shape requires modifying the Application class, which clearly breaks OCP.
Solution: Applying Open Closed Principle
To follow OCP:
- Move volume calculation logic to individual objects
- Use abstraction and polymorphism
- Keep the Application class unchanged
Example 3: OCP-Compliant Design
Step 1: Create an Abstract Base Class
abstract class GeoObject {
public abstract double getVolume();
}
Step 2: Extend Base Class for Cuboid
class Cuboid extends GeoObject {
public double length;
public double breadth;
public double height;
@Override
public double getVolume() {
return length * breadth * height;
}
}
Step 3: Extend Base Class for Sphere
class Sphere extends GeoObject {
public double radius;
@Override
public double getVolume() {
return (4.0 / 3) * Math.PI * radius * radius * radius;
}
}
Step 4: Keep Application Class Closed for Modification
class Application {
public double getTotalVolume(GeoObject[] objects) {
double volumeSum = 0;
for (GeoObject obj : objects) {
volumeSum += obj.getVolume();
}
return volumeSum;
}
}
Step 5: Main Class
public class Main {
public static void main(String[] args) {
GeoObject[] objects = new GeoObject[] {
new Cuboid(){{
length = 5; breadth = 10; height = 15;
}},
new Sphere(){{
radius = 5;
}}
};
Application app = new Application();
System.out.println("Total Volume: " + app.getTotalVolume(objects));
}
}
Output
Total Volume: 1840.6548245743668