Open Closed Principle in Java with Examples
Last Updated : 02 Jan, 2023
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); } }
OutputThe 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); } }
OutputThe 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); } }
OutputThe 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.
Similar Reads
Open Closed Design Principle in Java
Open Closed Design Principle is one of the most important design principles in the world of software development. It's part of a group of 5 design principles commonly known by the acronym "SOLID" S - Single Responsibility Principle O - Open Closed Principle L - Liskov Substitution Principle I - Inte
12 min read
Reader close() method in Java with Examples
The close() method of Reader Class in Java is used to close the stream and release the resources that were busy in the stream, if any. This method has following results: If the stream is open, it closes the stream releasing the resources If the stream is already closed, it will have no effect. If an
2 min read
Closures in Java with Examples
A method is a collection of statements that perform some specific task and return the result to the caller. A method can perform some specific task without returning anything. Methods allow us to reuse the code without retyping the code. In Java, every method must be part of some class that is diffe
5 min read
ObjectInputStream close() method in Java with examples
The close() method of the ObjectInputStream class in Java closes the input stream. Syntax: public void close() Parameters: This method does not accept any parameter. Return Value: This method does not returns anything. Below program illustrate the above method: Program 1: // Java program to illustra
1 min read
Throwable Class in Java with Examples
Classes and Objects are basic concepts of Object-Oriented Programming which revolve around real-life entities. A class is a user-defined blueprint or prototype from which objects are created. It represents the set of properties or methods that are common to all objects of one type. In this article,
7 min read
PushbackReader close() method in Java with Examples
The close() method of PushbackReader Class in Java is used to close the stream and release the resources that were busy in the stream, if any. This method has following results: If the stream is open, it closes the stream releasing the resources If the stream is already closed, it will have no effec
2 min read
Writer close() method in Java with Examples
The close() method of Writer Class in Java is used to close the writer. Closing a writer deallocates any value in it or any resources associated with it. The Writer instance once closed won't work. Also a Writer instance once closed cannot be closed again. Syntax: public void close() Parameters: Thi
2 min read
Different Types of Classes in Java with Examples
A class is a user-defined blueprint or prototype from which objects are created. Â It represents the set of properties or methods that are common to all objects of one type. In general, class declarations can include these components, in order: Â Modifiers: A class can be public or has default access
11 min read
Optional empty() method in Java with examples
The empty() method of java.util.Optional class in Java is used to get an empty instance of this Optional class. This instance do not contain any value. Syntax: public static <T> Optional<T> empty() Parameters: This method accepts nothing. Return value: This method returns an empty instan
1 min read
DRY (Donât Repeat Yourself) Principle in Java with Examples
DRY is simply an approach, or we can say, a different perspective to programmers. DRY stands for Don't Repeat Yourself. In Java, it means donât write the same code repeatedly. Suppose you are having the same code at many places in your program, then it means you are not following the DRY approach; Y
5 min read