In this tutorial, we will learn about Open Closed Design Principle in Java.Open closed principle is one of the SOLID principles.
Open Closed Design Principle dictates that “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”. This definition was provided by Bertrand Meyer.
Once we have written the class and tested it, it should not be modified again and again but it should open for extension.If we modify already test clasess, it may lead to lot of extras effort to test it back and also there can be chances for the introduction of new bugs.
Strategy Design Pattern is another example of Open Closed design Principle. Service class can use various strategies to perform certain tasks based on requirement so we will keep Service class closed but same time, System is open for extension, by introducing new Strategy which will implement Strategy interface. At runtime, you can call Service Class with any new Strategy, based upon your need.
Let’s understand with the help of a simple example.
You need to create two types(CSV and XML) of reports based on input type.Please note that there should be provision to add new report type in future.
Create an Enum called "ReportType.java" as below.
1 2 3 4 5 6 |
package org.arpit.java2blog; public enum ReportingType { CSV,XML; } |
Create Service class named ReportingService as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package org.arpit.java2blog; public class ReportingService { public void generateReportBasedOnType(ReportingType reportingType) { System.out.println("==================================="); System.out.println("Generating report based on Type"); System.out.println("==================================="); if("CSV".equalsIgnoreCase(reportingType.toString())) { generateCSVReport(); } else if("XML".equalsIgnoreCase(reportingType.toString())) { generateXMLReport(); } } private void generateCSVReport() { System.out.println("Generate CSV Report"); } private void generateXMLReport() { System.out.println("Generate XML Report"); } } |
Create a main class named "GenerateReportMain.java" which will called ReportingService to generate report.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package org.arpit.java2blog; public class GenerateReportMain { public static void main(String[] args) { ReportingService rs=new ReportingService(); // Generate CSV file rs.generateReportBasedOnType(ReportingType.CSV); System.out.println(); // Generate XML file rs.generateReportBasedOnType(ReportingType.XML); } } |
Output:
Generating report based on Type
===================================
Generate CSV Report
===================================
Generating report based on Type
===================================
Generate XML Report
As you can see, this is simple code which is working fine.You have tested code and found out that you are able to generate report based on the type.
Now you need to create one more report type i.e. Excel.If you notice, if you need to make changes as below:
1) You need to make changes in Enum ReportingType.
1 2 3 4 5 6 |
package org.arpit.java2blog; public enum ReportingType { CSV,XML,EXCEL; } |
2) You need to make changes in ReportingService class which you have already tested.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package org.arpit.java2blog; public class ReportingService { public void generateReportBasedOnType(ReportingType reportingType) { System.out.println("==================================="); System.out.println("Generating report based on Type"); System.out.println("==================================="); if("CSV".equalsIgnoreCase(reportingType.toString())) { generateCSVReport(); } else if("XML".equalsIgnoreCase(reportingType.toString())) { generateXMLReport(); } else if("Excel".equalsIgnoreCase(reportingType.toString())) { generateExcelReport(); } } private void generateCSVReport() { System.out.println("Generate CSV Report"); } private void generateXMLReport() { System.out.println("Generate XML Report"); } private void generateExcelReport() { System.out.println("Generate Excel Report"); } } |
Now you can generate Excel reports as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package org.arpit.java2blog; public class GenerateReportMain { public static void main(String[] args) { ReportingService rs=new ReportingService(); // Generate CSV file rs.generateReportBasedOnType(ReportingType.CSV); System.out.println(); // Generate XML file rs.generateReportBasedOnType(ReportingType.XML); System.out.println(); // Generate Excel file rs.generateReportBasedOnType(ReportingType.EXCEL); } } |
Output:
Generating report based on Type
===================================
Generate CSV Report
===================================
Generating report based on Type
===================================
Generate XML Report
===================================
Generating report based on Type
===================================
Generate Excel Report
As you can see, we have to modify at many places which we have already tested and we need to retest all the functionalities again.
Open Closed Design Principle
Let’s see how open closed design principle will be able to solve the problem.
Create ReportingService.java as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package org.arpit.java2blog; public class ReportingService { public void generateReportBasedOnStrategy(ReportingStrategy reportingStrategy) { System.out.println("==================================="); System.out.println("Generating report based on Strategy"); System.out.println("==================================="); reportingStrategy.generateReport(); System.out.println(); } } |
Create an interface called ReportingStrategy as below.
1 2 3 4 5 6 7 |
package org.arpit.java2blog; public interface ReportingStrategy { void generateReport(); } |
Create a class named "CSVReportingStrategy.java" for generating CSV reports
1 2 3 4 5 6 7 8 9 10 11 |
package org.arpit.java2blog; public class CSVReportingStrategy implements ReportingStrategy { @Override public void generateReport() { System.out.println("Generate CSV Report"); } } |
Create a class named "XMLReportingStrategy.java" for generating XML reports
1 2 3 4 5 6 7 8 9 10 11 |
package org.arpit.java2blog; public class XMLReportingStrategy implements ReportingStrategy { @Override public void generateReport() { System.out.println("Generate XML Report"); } } |
Let’s create a main class GenerateReportMain.java now.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package org.arpit.java2blog; public class GenerateReportMain { public static void main(String[] args) { ReportingService rs=new ReportingService(); //Generate CSV report ReportingStrategy csvReportingStrategy=new CSVReportingStrategy(); rs.generateReportBasedOnStrategy(csvReportingStrategy); //Generate XML report ReportingStrategy xmlReportingStrategy=new XMLReportingStrategy(); rs.generateReportBasedOnStrategy(xmlReportingStrategy); } } |
Output:
Generating report based on Type
===================================
Generate CSV Report
===================================
Generating report based on Type
===================================
Generate XML Report
Let’s say you want to generate Excel reports.You need to create below changes:
Create another class named "ExcelReportingStrategy.java" as below.
1 2 3 4 5 6 7 8 9 10 11 |
package org.arpit.java2blog; public class ExcelReportingStrategy implements ReportingStrategy { @Override public void generateReport() { System.out.println("Generate Excel Report"); } } |
Change in GenerateReportMain.java to add calling code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package org.arpit.java2blog; public class GenerateReportMain { public static void main(String[] args) { ReportingService rs=new ReportingService(); //Generate CSV report ReportingStrategy csvReportingStrategy=new CSVReportingStrategy(); rs.generateReportBasedOnStrategy(csvReportingStrategy); //Generate XML report ReportingStrategy xmlReportingStrategy=new XMLReportingStrategy(); rs.generateReportBasedOnStrategy(xmlReportingStrategy); //Generate Excel report ReportingStrategy ExcelReportingStrategy=new ExcelReportingStrategy(); rs.generateReportBasedOnStrategy(ExcelReportingStrategy); } } |
Output:
Generating report based on Strategy
===================================
Generate CSV Report
===================================
Generating report based on Strategy
===================================
Generate XML Report
===================================
Generating report based on Strategy
===================================
Generate Excel Report
As you can see, we did not make any changes ReportingService which was already tested.We just added new class "ExcelReportingStrategy" which enabled us to generate Excel report.
That’s all about Open Closed Design Principle in Java.