Factory Pattern
It is a Creational Pattern as this pattern deals with the best ways to create an object.
We are developing an application which has to get data from third party and display it in our website.
Third party data could be in the form of Excel,text file or anything which can change later.
Let’s create a class for each data type representation
Create DataFromThirdPartyExcel.java
- package com.kb.factory.problem;
- public class DataFromThirdPartyExcel {
- void getData(){
- System.out.println("logic to get excel data from third party");
- }
- void display(){
- System.out.println("logic to display excel data");
- }
- }
package com.kb.factory.problem; public class DataFromThirdPartyExcel { void getData(){ System.out.println("logic to get excel data from third party"); } void display(){ System.out.println("logic to display excel data"); } }
Create DataFromThirdPartyTextFile.java
- package com.kb.factory.problem;
- public class DataFromThirdPartyTextFile {
- void getData(){
- System.out.println("logic to get text file data from third party");
- }
- void display(){
- System.out.println("logic to display text file data");
- }
- }
package com.kb.factory.problem; public class DataFromThirdPartyTextFile { void getData(){ System.out.println("logic to get text file data from third party"); } void display(){ System.out.println("logic to display text file data"); } }
Create Client.java
- package com.kb.factory.problem;
- public class Client {
- public static void main(String[] args) {
- //To get Text data
- getDataFormThirdPartyAndDisplay("text");
- //To get Excel data
- getDataFormThirdPartyAndDisplay("excel");
- }
- static void getDataFormThirdPartyAndDisplay(String dataType){
- if(dataType.equalsIgnoreCase("text")){
- DataFromThirdPartyTextFile textFile = new DataFromThirdPartyTextFile();
- textFile.getData();
- textFile.display();
- }
- else if(dataType.equalsIgnoreCase("excel")){
- DataFromThirdPartyExcel thirdPartyExcel = new DataFromThirdPartyExcel();
- thirdPartyExcel.getData();
- thirdPartyExcel.display();
- }
- else
- System.out.println("invalid data type");
- }
- }
package com.kb.factory.problem; public class Client { public static void main(String[] args) { //To get Text data getDataFormThirdPartyAndDisplay("text"); //To get Excel data getDataFormThirdPartyAndDisplay("excel"); } static void getDataFormThirdPartyAndDisplay(String dataType){ if(dataType.equalsIgnoreCase("text")){ DataFromThirdPartyTextFile textFile = new DataFromThirdPartyTextFile(); textFile.getData(); textFile.display(); } else if(dataType.equalsIgnoreCase("excel")){ DataFromThirdPartyExcel thirdPartyExcel = new DataFromThirdPartyExcel(); thirdPartyExcel.getData(); thirdPartyExcel.display(); } else System.out.println("invalid data type"); } }
Now look at the client code which has tight coupling with the excel class and text file class.
In future if we want to add one more data representation say PDF then again we have to go to the client code and change the behavior by adding one more else if condition.
- else if(dataType.equalsIgnoreCase("pdf")){
- DataFromThirdPartyPDF thirdPartypPdf = new DataFromThirdPartyPdf();
- thirdPartypPdf.getData();
- thirdPartypPdf.display();
- }
else if(dataType.equalsIgnoreCase("pdf")){ DataFromThirdPartyPDF thirdPartypPdf = new DataFromThirdPartyPdf(); thirdPartypPdf.getData(); thirdPartypPdf.display(); }
So we are tending to change client code for every business needs changes.
So why can’t we separate this changing behavior and keep in some separate place.
Yes that separate place we call it as a Factory.
Factory pattern separates the object creation code (in fact frequently changing code) and put it in a place apart from client code.
Let’s see how can we achieve this
Create Interface DataFromThirdParty.java
- package com.kb.factory.solution;
- public interface DataFromThirdParty {
- void getData();
- void display();
- }
package com.kb.factory.solution; public interface DataFromThirdParty { void getData(); void display(); }
Create DataFromThirdPartyExcel.java
- package com.kb.factory.solution;
- public class DataFromThirdPartyExcel implements DataFromThirdParty {
- public void getData(){
- System.out.println("logic to get excel data from third party");
- }
- public void display(){
- System.out.println("logic to display excel data");
- }
- }
package com.kb.factory.solution; public class DataFromThirdPartyExcel implements DataFromThirdParty { public void getData(){ System.out.println("logic to get excel data from third party"); } public void display(){ System.out.println("logic to display excel data"); } }
Create DataFromThirdPartyTextFile.java
- package com.kb.factory.solution;
- public class DataFromThirdPartyTextFile implements DataFromThirdParty {
- public void getData(){
- System.out.println("logic to get text file data from third party");
- }
- public void display(){
- System.out.println("logic to display text file data");
- }
- }
package com.kb.factory.solution; public class DataFromThirdPartyTextFile implements DataFromThirdParty { public void getData(){ System.out.println("logic to get text file data from third party"); } public void display(){ System.out.println("logic to display text file data"); } }
Create DataFromThirdPartyFactory.java
- package com.kb.factory.solution;
- public class DataFromThirdPartyFactory {
- DataFromThirdParty getDataFromThirdParty(String dataType){
- if(dataType.equalsIgnoreCase("text")){
- return new DataFromThirdPartyTextFile();
- }
- else if(dataType.equalsIgnoreCase("excel")){
- return new DataFromThirdPartyExcel();
- }
- else
- System.out.println("invalid data type");
- return null;
- }
- }
package com.kb.factory.solution; public class DataFromThirdPartyFactory { DataFromThirdParty getDataFromThirdParty(String dataType){ if(dataType.equalsIgnoreCase("text")){ return new DataFromThirdPartyTextFile(); } else if(dataType.equalsIgnoreCase("excel")){ return new DataFromThirdPartyExcel(); } else System.out.println("invalid data type"); return null; } }
Create Client.java
- package com.kb.factory.solution;
- public class Client {
- public static void main(String[] args) {
- DataFromThirdParty dataFromThirdParty;
- DataFromThirdPartyFactory thirdPartyFactory = new DataFromThirdPartyFactory();
- //To get Text data
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("text");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
- //To get Excel data
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("excel");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
- }
- }
package com.kb.factory.solution; public class Client { public static void main(String[] args) { DataFromThirdParty dataFromThirdParty; DataFromThirdPartyFactory thirdPartyFactory = new DataFromThirdPartyFactory(); //To get Text data dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("text"); dataFromThirdParty.getData(); dataFromThirdParty.display(); //To get Excel data dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("excel"); dataFromThirdParty.getData(); dataFromThirdParty.display(); } }
Now client using factory object to get the required object.
Now if we want to add new functionality to get data in the PDF form, then it needs no change at client with respect to data representation logic . only client has to include a call to the PDF data type.
Let’s see above change in factory pattern
Obviously Change in factory pattern means change inside factory class only.
Create a new functionality but implement it with the interface DataFromThirdParty
As we should do program to Interface not program to Implementation.
Create DataFromThirdPartyPDF.java
- package com.kb.factory.solution;
- public class DataFromThirdPartyPDF implements DataFromThirdParty{
- public void getData(){
- System.out.println("logic to get pdf file data from third party");
- }
- public void display(){
- System.out.println("logic to display pdf file data");
- }
- }
package com.kb.factory.solution; public class DataFromThirdPartyPDF implements DataFromThirdParty{ public void getData(){ System.out.println("logic to get pdf file data from third party"); } public void display(){ System.out.println("logic to display pdf file data"); } }
Now see how Factory class gets one extra else if statement
Create DataFromThirdPartyFactory.java
- package com.kb.factory.solution;
- public class DataFromThirdPartyFactory {
- DataFromThirdParty getDataFromThirdParty(String dataType){
- if(dataType.equalsIgnoreCase("text")){
- return new DataFromThirdPartyTextFile();
- }
- else if(dataType.equalsIgnoreCase("excel")){
- return new DataFromThirdPartyExcel();
- }
- else if(dataType.equalsIgnoreCase("pdf")){
- return new DataFromThirdPartyPDF();
- }
- else
- System.out.println("invalid data type");
- return null;
- }
- }
package com.kb.factory.solution; public class DataFromThirdPartyFactory { DataFromThirdParty getDataFromThirdParty(String dataType){ if(dataType.equalsIgnoreCase("text")){ return new DataFromThirdPartyTextFile(); } else if(dataType.equalsIgnoreCase("excel")){ return new DataFromThirdPartyExcel(); } else if(dataType.equalsIgnoreCase("pdf")){ return new DataFromThirdPartyPDF(); } else System.out.println("invalid data type"); return null; } }
That’s it new functionality has been implemented without client knows about it.
Now client can use this new functionality just by calling same factory method but passing different string for pdf as below
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("pdf");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("pdf"); dataFromThirdParty.getData(); dataFromThirdParty.display();
Create Client.java
- package com.kb.factory.solution;
- public class Client {
- public static void main(String[] args) {
- DataFromThirdParty dataFromThirdParty;
- DataFromThirdPartyFactory thirdPartyFactory = new DataFromThirdPartyFactory();
- //To get Text data
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("text");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
- //To get Excel data
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("excel");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
- //To get PDF data
- dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("pdf");
- dataFromThirdParty.getData();
- dataFromThirdParty.display();
- }
- }
package com.kb.factory.solution; public class Client { public static void main(String[] args) { DataFromThirdParty dataFromThirdParty; DataFromThirdPartyFactory thirdPartyFactory = new DataFromThirdPartyFactory(); //To get Text data dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("text"); dataFromThirdParty.getData(); dataFromThirdParty.display(); //To get Excel data dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("excel"); dataFromThirdParty.getData(); dataFromThirdParty.display(); //To get PDF data dataFromThirdParty = thirdPartyFactory.getDataFromThirdParty("pdf"); dataFromThirdParty.getData(); dataFromThirdParty.display(); } }
The same Factory pattern has been used in spring container to get the required object using XM.