The most successful people in any walks of lives may not be the most talented ones but are definately the most passionate & dedicated ones.

Thursday, September 16, 2010

Factory design pattern [with sample implementation in java]

Definition -- Factory design pattern
Provides an abstraction (usually via an interface) and lets subclass / implementing classes decide which class / method should be instantiated / called, based on the conditions or parameters given.

Intent :-
Factory Method lets a class defer instantiation to subclasses.
To delegate responsibility among different objects and this kind of partitioning is good since it encourages Encapsulation and Delegation.

Discussion :-
Lets leave aside java concepts for a moment and think what a factory in general does? Yes, ask this question to yourself that what any typical factory [say a Toy factory which makes different kind of toys some in shape of aeroplane, some in shape of a racing car] functions?

Now what a factory owner will do to maximize his profit and allow new toys to be build seamlessly is exactly the same what we are going to do in our java classes.

What the toy factory owner will do is that in one chamber of the factory, he will have molten plaster-of-paris (or other material) and then bring it to another chamber where he has kept different toy structures like in the shape of aeroplane / jeep etc and then pour the molten plaster-of-paris into those structures and when it solidifies, he gets the toy of that shape. So the molten plaster-of-paris doesn't know until at the end moment that which structure it would be poured in and what toy would come out but then for sure it would be a toy.

Now lets see how we utilize this concept in java. The molten plaster-of-paris is equivalent to a interface i.e. a standard agreement that it can be converted into any toy provided its poured into a shape/structure.
The structures of aeroplane/jeep are the concrete subclasses which implement the contract with the molten P-o-P. Now what toy would turn out is not known until its poured is similar to getting the objects at runtime.

This we can say that...
Factory Method is to creating objects <==is similar to==> Template to implementing an algorithm/rule [molten P-o-P into structures].
In technical terms, A superclass specifies all standard and generic behavior and then delegates the creation details to subclasses that are supplied by the client.

Why to use Factory design pattern?
We would use a pattern only if its benefits us/our solution in some way or the other. So benefits of Factory pattern are:-
  • A family of objects is separated by using shared interface.
  • Hide concrete classes from the client.
  • The advantage of a Factory Method is that it can return the same instance multiple times, or can return a subclass rather than an object of that exact type.
  • The "new" operator is considered harmful. There is a difference between requesting an object and creating one. The "new" operator always creates an object, and fails to encapsulate object creation. A Factory Method enforces that encapsulation, and allows an object to be requested without inextricable coupling to the act of creation.
Where to use a Factory pattern?
  • A class cannot anticipate its subclasses, which must be created.
  • A sample scenario:- One typical use of the Factory Pattern in an Enterprise JavaBean (EJB) Application: An entity bean is an object representation of persistent data that are maintained in a permanent data store, such as a database. A primary key identifies each instance of an entity bean. Entity beans can be created by creating an object using an object factory Create method. Similarly, Session beans can be created by creating an object using an object factory Create method.
Sample implementation of Factory pattern [in java programming language] :-
  • Here, I have used 6 [classes and interfaces] to provide a sample implementation.
  • The purpose of each class and interface is explained at the beginning of the source code along with other important points.
  • Here you can begin looking at FactoryPatternDemo.java class which has the main() method as a starting point.

(1) ************ start of Constants.java ************
/**
* Purpose:- Class to accomodate constants at one place.
*/
package factoryPattern;

/**
* @author Vinay K Mudgil
*
*/
public class Constants {

public static final String CONSOLE_LOG = "consoleWriter";
public static final String FILE_LOG = "fileWriter";

public static final String logFileName = "TestLogFile.log";
public static final String logFileLocation = "/home/vm234069/Desktop/";
}
************ end of Constants.java ************


(2) ************ start of ConsoleLogWriter.java ************
/**
* Purpose:- The usage of this class is to implement the console logging functionality
*/
package factoryPattern;

/**
* @author Vinay K Mudgil
*
*/
public class ConsoleLogWriter implements ILogWriter {

private boolean isDebugModeOn = false;

public void setDebugMode(boolean value) {
this.isDebugModeOn = value;
}

public void printErrorStatement(String errMsg) {
if (isDebugModeOn)
System.out.println("Printing error message on console.");
}

public void printDebugStatement(String debugMsg) {
if (isDebugModeOn)
System.out.println("Printing debug message on console.");
}

}
************ end of ConsoleLogWriter.java ************

(3) ************ start of FactoryPatternDemo.java ************
/**
* Purpose:- To demonstrate factory pattern.
*/
package factoryPattern;

/**
* @author Vinay K Mudgil
*
*/
public class FactoryPatternDemo {

public static void main(String[] args) {

//First lets write to a console.
ConsoleLogWriter clg = (ConsoleLogWriter) LogFactory.getLogWriter(Constants.CONSOLE_LOG);
clg.setDebugMode(true);
clg.printDebugStatement("debug message");
clg.printErrorStatement("error message");

//now lets write to a log file.
FileLogWriter flw = (FileLogWriter) LogFactory.getLogWriter(Constants.FILE_LOG);
flw.setDebugMode(true);
flw.openLogFile();
flw.printDebugStatement("debug message");
flw.printErrorStatement("error message");
flw.closeLogFile();

}

}
************ end of FactoryPatternDemo.java ************


(4) ************ start of FileLogWriter.java************
/**
* Purpose:- The usage of this class is to implement the console logging functionality
*/
package factoryPattern;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
* @author Vinay K Mudgil
*
*/
public class FileLogWriter extends Constants implements ILogWriter{

private boolean isDebugModeOn = false;
private BufferedWriter bw = null;


public void openLogFile() {
try {
bw = new BufferedWriter(new FileWriter(logFileLocation+logFileName));
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}


public void setDebugMode(boolean value) {
this.isDebugModeOn = value;
}


public void printErrorStatement(String errMsg) {
try {
if(bw != null) {
bw.write(errMsg+" -- Printing error message in log file.\n");
bw.flush();
}
} catch (IOException ioe) {
System.out.println("IOException via writing error Message");
} catch (Exception e) {
System.out.println("Exception via writing error Message");
}
}

public void printDebugStatement(String debugMsg) {
try {
if(bw != null) {
bw.write(debugMsg +" -- Printing debug message in log file.\n");
bw.flush();
}
} catch (IOException ioe) {
System.out.println("IOException via writing debug Message");
} catch (Exception e) {
System.out.println("Exception via writing debug Message");
}

}

public void closeLogFile() {

try {
if(bw != null) {
bw.close();
}
} catch (IOException ioe) {
System.out.println("IOException while closing the file.");
}
}

}

************ end of FileLogWriter.java ************


(5) ************ start of ILogWriter.java ************
/**
* Purpose:- The purpose of this interface is to provide an agreement of some basic functionalities which any generic
* LogWriter should provide
*/
package factoryPattern;

/**
* @author Vinay K Mudgil
*
*/
public interface ILogWriter {

//turn on/off the debug mode
public void setDebugMode(boolean value);

//write an error statement
public void printErrorStatement(String errMsg);

//write an debug statement
public void printDebugStatement(String debugMsg);

} //enf of Interface definition
************ end of ILogWriter.java ************


(6) ************ start of LogFactory.java ************
/**
* Purpose:- This is the factory class which actually creates the concrete class type depending on which is required by the client.
*/
package factoryPattern;

/**
* @author Vinay K Mudgil
*
*/
public class LogFactory extends Constants {

// method returning appropriate class object
public static ILogWriter getLogWriter(String writerType) {
if (writerType.equals(Constants.CONSOLE_LOG)) {
return new ConsoleLogWriter();
} else if (writerType.equals(Constants.FILE_LOG)) {
return new FileLogWriter();
}

System.out.println("illegal logging selection...");
return null;
}
}

************ end of LogFactory.java ************

Please feel free to comment on concepts 'n' sample code snippet provided above & spare me for any typo's. Happy to learn !!!

Thanks !!!

3 comments:

  1. I liked the way You have explained.
    Thanks for sharing.

    ReplyDelete
  2. Nice post vinay. I like the idea of Factory method, It gives more control on maintenance part of software life cycle. even Josua Bloach has suggested importance of static factory method in Effective Java. I have also blogged about factory method pattern in Java, let me know how do you find it.

    ReplyDelete