Tuesday, November 19, 2024
Google search engine
HomeLanguagesJavaOpen Closed Principle in Java with Examples

Open Closed Principle in Java with Examples

In software development, the use of object-oriented design is crucial. It helps to write flexible, scalable, and reusable code. It is recommended that the developers follow SOLID principles when writing a code. One of the five SOLID principles is the open/closed principle. The principle states that software entities like class, modules, functions, etc.; should be able to extend a class behavior without modifying it. This principle separates the existing code from modified mode to provide better stability, maintainability and minimizes the changes in the code. In a nutshell, the developer must need to change only a specific part of the code (a class or a function) every time a requirement changes.

Using a statically typed language like Java, C#, etc. the open/closed principle is generally achieved by using inheritance and polymorphism. Let’s understand it with a few examples.

Implementation: 

Program to calculate the volume in which let us consider the task of building an application that calculates the volumes of all the geometric objects.

  • The Cuboid class stores dimensions of the cuboid
  • Later on, the Application class calculates the total volume of the geometric objects–which are only cuboids currently.
  • Run class helps to run the whole program.

Example 1:

Java




// Java Program to illustrate Open Closed Principle
 
// Class 1
// Helper class
// To store dimensions of a cuboid
// length, breadth and height
class Cuboid {
     
    // Member variables
    public double length;
    public double breadth;
    public double height;
}
 
// Class 2
// Helper class
// To calculate the volume of geometric objects
class Application {
 
    // It returns the total volume of the geometric objects
    public double get_total_volume(Cuboid[] geo_objects)
    {
        // Variable to store total volume
        double vol_sum = 0;
 
        // Iteratively calculating the volume of each object
        // and adding it to the total volume
        for (Cuboid geo_obj : geo_objects) {
             
            // Iteratively calculating the volume of each object
            // and adding it to the total volume
            vol_sum += geo_obj.length * geo_obj.breadth
                       * geo_obj.height;
        }
 
        // returning the to total volume
        return vol_sum;
    }
}
 
// Class 3
// Main Class
// To demonstrate working of all classes
public class GFG {
 
    // Main driver method
    public static void main(String args[])
    {
        // Initializing a cuboid one & declaring dimensions by
        // creating an object of Cuboid class in main() method
        Cuboid cb1 = new Cuboid();
 
        // Custom entries
        cb1.length = 5;
        cb1.breadth = 10;
        cb1.height = 15;
 
        // Similarly, initializing a cuboid2 and declaring dimensions
        // by creating object of Cuboid class in the main() method
        Cuboid cb2 = new Cuboid();
 
        // Custom entries
        cb2.length = 2;
        cb2.breadth = 4;
        cb2.height = 6;
 
        // Initializing a cuboid3 and declaring dimensions by
        // creating object of Cuboid class in the main() method
        Cuboid cb3 = new Cuboid();
 
        // Custom entries
        cb3.length = 3;
        cb3.breadth = 12;
        cb3.height = 15;
 
        // Now, declaring andinitializing Array of cuboids
        Cuboid[] c_arr = new Cuboid[3];
        c_arr[0] = cb1;
        c_arr[1] = cb2;
        c_arr[2] = cb3;
 
        // Initializing the Application class
        Application app = new Application();
         
        // Getting the total volume
        // using get_total_volume
        double vol = app.get_total_volume(c_arr);
         
        // Print and Display the Total Volume
        System.out.println("The total volume is " + vol);
    }
}


Output

The total volume is 1338.0

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:

Java




// Java Program to illustrate Open Closed Principle
 
// class 1
// Helper class
// To store dimensions of a cuboid
// used to store length, breadth and height of a cuboid
class Cuboid {
 
    // Member variables of this class
    public double length;
    public double breadth;
    public double height;
}
 
// Class 2
// Helper class
// To store dimensions of a sphere
class Sphere {
 
    // Storing radius of a sphere
    public double radius;
}
 
// Class 3
// Helper class
// This class helps to calculate the volume of geometric
// objects
class Application {
 
    // Returning the total volume of the geometric objects
    public double get_total_volume(Cuboid[] c_geo_objects,
                                   Sphere[] s_geo_objects)
    {
        // Variable used to store total volume
        double vol_sum = 0;
 
        // Iteratively calculating the volume of each Cuboid
        // and adding it to the total volume
 
        // Iterating using for each loop to
        // calculate the volume of a cuboid
        for (Cuboid geo_obj : c_geo_objects) {
 
            vol_sum += geo_obj.length * geo_obj.breadth
                       * geo_obj.height;
        }
 
        // Iterating using for each loop to
        // calculate the volume of a cuboid
        for (Sphere geo_obj : s_geo_objects) {
 
            // Iteratively calculating the volume of each
            // Sphere and adding it to the total volume
            vol_sum += (4 / 3) * Math.PI * geo_obj.radius
                       * geo_obj.radius * geo_obj.radius;
        }
 
        // Returning the to total volume
        return vol_sum;
    }
}
 
// Class 4
// Main class
// To demonstrate working of all classes
public class GFG {
 
    //  Main driver method
    public static void main(String args[])
    {
        // Initializing a cuboid one as well as declaring
        // its dimensions.
        Cuboid cb1 = new Cuboid();
        cb1.length = 5;
        cb1.breadth = 10;
        cb1.height = 15;
 
        // Initializing a cuboid two as well as declaring
        // its dimensions.
        Cuboid cb2 = new Cuboid();
        cb2.length = 2;
        cb2.breadth = 4;
        cb2.height = 6;
 
        ////Initializing a cuboid three as well as declaring
        /// its dimensions.
        Cuboid cb3 = new Cuboid();
        cb3.length = 3;
        cb3.breadth = 12;
        cb3.height = 15;
 
        // Initializing and declaring an array of cuboids
        Cuboid[] c_arr = new Cuboid[3];
        c_arr[0] = cb1;
        c_arr[1] = cb2;
        c_arr[2] = cb3;
 
        // Initializing a sphere one as well as declaring
        // its dimension.
        Sphere sp1 = new Sphere();
        sp1.radius = 5;
 
        // Initializing a sphere two as well as declaring
        // its dimension.
        Sphere sp2 = new Sphere();
        sp2.radius = 2;
 
        // Initializing a sphere three as well as declaring
        // its dimension.
        Sphere sp3 = new Sphere();
        sp3.radius = 3;
 
        // Initializing and declaring an array of spheres
        Sphere[] s_arr = new Sphere[3];
        s_arr[0] = sp1;
        s_arr[1] = sp2;
        s_arr[2] = sp3;
 
        // Initializing Application class
        Application app = new Application();
 
        // Getting the total volume
        // using get_total_volume
        double vol = app.get_total_volume(c_arr, s_arr);
 
        // Print and display the total volume
        System.out.println("The total volume is " + vol);
    }
}


Output

The total volume is 1840.6548245743668

Output Explanation:

As we can see the application class had to be changed to accommodate the sphere. Any changes in a code can lead to some unexpected errors in the future–so it is not advisable to change the well-tested code every time requirements change. Let’s try to apply the Open Close principle and see if we can add a sphere (a new type of object) without making any changes to the application class.

Solution:

  • Create an abstract class that serves as a base class for all types of objects.
  • All the geometric objects have a set of dimensions and a get_volume method (both of which are different for each type of object).
  • For each type of object (a geometric object in this case) inherit the ‘Geo_object’ class, add the dimensions for that type of object and override the ‘get_volume‘ method.
  • As it is apparent that by shifting the volume calculation from the ‘Application’ class to a different class, adding a new type of geometric object would not require changing the ‘Application’ class.

Example 3:

Java




// Java Program to illustrate Open Closed Principle
 
// Importing all classes from java.math package
// to compute mathematic calculations
import java.math.*;
 
// Class 1
// Helper Class
// Abstract class--which needs to be extended
abstract class Geo_objects {
 
   // Abstract function--which needs to overriden
    public abstract double get_volume();
}
 
// Class 2
// Helper Class
// Extending the Geo_objects to fit cuboid dimensions
class Cuboid_2 extends Geo_objects {
     
    // used to store length, breadth and height of a cuboid
 
    public double length;
    public double breadth;
    public double height;
 
    // overrided function to calculate
    // the volume of a cuboid
    // @Override
    public double get_volume()
    {
        return length * breadth * height;
    }
}
 
// Class 3
// Helper Class
// Extending Geo_objects to fit sphere dimension
 class Sphere_2 extends Geo_objects {
     
    // To store radius of a sphere
    public double radius;
 
    // Overrided function to calculate
    //  the volume of a sphere
     
    //@Override
    public double get_volume()
    {
        return (4 / 3) * Math.PI * radius * radius * radius;
    }
}
 
// Class 4
// Helper class
// To calculate the volume of geometric objects
class Application {
 
    public double
        get_total_volume(Geo_objects[] geo_objects)
    {
        // Initially initializing sum to zero
        double vol_sum = 0;
 
        // Iterating using for each loop
        for (Geo_objects geo_obj : geo_objects) {
            vol_sum += geo_obj.get_volume();
        }
  
        return vol_sum;
    }
}
 
// Class 5
// Main class
// To demonstrate working of all classes
public class GFG {
 
    // Main driver method
    public static void main(String args[])
    {
        // Initializing cuboid1 as well as declaring
        // its dimensions.
        Cuboid_2 cb1 = new Cuboid_2();
 
        // Custom entries
        cb1.length = 5;
        cb1.breadth = 10;
        cb1.height = 15;
 
        // Initializing Cuboid2 as well as declaring
        // its dimensions.
        Cuboid_2 cb2 = new Cuboid_2();
        cb2.length = 2;
        cb2.breadth = 4;
        cb2.height = 6;
 
        // initializing Cuboid3 as well as declaring
        // its dimensions.
        Cuboid_2 cb3 = new Cuboid_2();
        cb3.length = 3;
        cb3.breadth = 12;
        cb3.height = 15;
 
        // initializing Sphere1 as well as declaring
        // its dimension.
        Sphere_2 sp1 = new Sphere_2();
        sp1.radius = 5;
 
        // initializing Sphere2 as well as declaring
        // its dimension.
        Sphere_2 sp2 = new Sphere_2();
        sp2.radius = 2;
 
        // initializing Sphere3 as well as declaring
        // its dimension.
        Sphere_2 sp3 = new Sphere_2();
        sp3.radius = 3;
 
        // Now, initializing and declaring
        // an array of Geo_objects
        Geo_objects[] g_arr = new Geo_objects[6];
 
        // Setting Geo_objects to cuboid class
        g_arr[0] = cb1;
        g_arr[1] = cb2;
        g_arr[2] = cb3;
 
        // Setting Geo_objects to sphere class
        g_arr[3] = sp1;
        g_arr[4] = sp2;
        g_arr[5] = sp3;
 
        // Initializing the Application class
        Application app = new Application();
         
        // Getting the total volume
        // using get_total_volume
        double vol = app.get_total_volume(g_arr);
 
        // Printing total volume
        System.out.println("The total volume is " + vol);
    }
}


Output

The total volume is 1840.6548245743668

Output Explanation:

The Application class is closed for modification. Please note there may be other ways to achieve the Open Close principle–ours is just one of the possible approaches.

On taking an overview, we found that our first approach wasn’t open for extension and required modification in the code to accommodate new requirements (new geometric objects) . While the second approach was open for extension and adding new requirements can be done without modifying any existing code. The second approach helps to achieve robustness in the whole program.

RELATED ARTICLES

Most Popular

Recent Comments