Factory method design pattern belongs to creational patterns. This pattern is also known as virtual constructor pattern. This pattern is designed to create an object in a smart way, smart way in the sense that in general, we use new
operator in Java to create an object but the new
operator can only be used when the client application knows in advance which class's object has to be created?
At times, among subclasses in a class hierarchy (where subclasses may override the parent class's method to offer a different type of functionality for the same method) client application may only know that it needs to access a class from within the class hierarchy, but does not know exactly which class among the set of subclasses of the parent class is to be selected. And here, FACTORY METHOD DESIGN PATTERN proves to be useful.
A simple factory method design pattern creates an object of one of several possible classes in inheritance hierarchy depending on the data provided to it. In this pattern, client application does not specify the class name whose object is to be created rather it provides some data to factory method in order to create an object and factory method itself decides which class's object should be created on behalf of the data provided to it.
The most challenging part in this pattern is to implement the class selection criteria to instantiate an appropriate class from the hierarchy to create an object.
In factory method design pattern mainly three classes/interfaces are involved, first, the factory class that creates an object from a given class hierarchy, second, an interface which is implemented by the concrete classes; objects of those classes will be created by factory class depending upon the input parameters, and third, an application object that creates one or more objects of interface's implementer classes with the help of factory class in order to use them for its purpose.
Here, we are coding a simple factory method design pattern. We are developing a functionality to log messages for an application. In order to implement logging functionality by using factory method design pattern we define a Java interface Logger
that will be used to create references by the client objects to log messages and will be implemented by concrete logger classes. Interface Logger
has a method logMessage
that will be implemented by ConsoleLogger
and FileLogger
. ConsoleLogger
will display log messages on console, while FileLogger
will direct log messages to a text file.
There will be a third class Factory
that will be used to create objects of FileLogger
or ConsoleLogger
. Driver class FactoryMethodPattern
will use the services provided by the Logger
implementers (ConsoleLogger
and FileLogger
). Application message logging configuration is specified by using the logger.properties
property file, which has a field FileLogging = ON/OFF
.
Depending upon the value of the FileLogging
property, an appropriate Logger
implementer needs to be used to log messages. For example, if the FileLogging
property is set to ON
, messages are to be logged to a file and hence a FileLogger
object can be used to log messages. Similarly, if the FileLogging
property is set to OFF
, messages are to be displayed on the console and hence a ConsoleLogger
object can be used.
The following figure shows how various classes are associated to each other in factory method design pattern.
Following program presents Java code for above class diagram of factory method design pattern. To execute the following piece of code you have to create a text file logger.properties
within the same directory your .java
program file is stored containing a line FileLogging = ON
or FileLogging = OFF
.
If you keep FileLogging = ON
, log messages will be recorded in a text file Filelog.log
in the same directory your program is being executed from. If Filelog.log
is already present there, log messages will be appended to existing file else Filelog.log
will be created by the program.
import java.io.File; import java.io.FileWriter; import java.io.BufferedWriter; import java.io.IOException; import java.util.Properties; interface Logger { public void logMessage(String message); } class FileLogger implements Logger { public void logMessage(String message) { try { File file =new File("Filelog.log"); //create file if doesn't exist if(!file.exists()) { file.createNewFile(); } //true = append file FileWriter fileWritter = new FileWriter(file.getName(),true); BufferedWriter bufferWritter = new BufferedWriter(fileWritter); bufferWritter.write(message); bufferWritter.close(); } catch(IOException e) { e.printStackTrace(); } System.out.println("Message logged in file: " + message); } } class ConsoleLogger implements Logger { public void logMessage(String message) { System.out.println("Console: " + message); } } class Factory { public Logger getLogger() { if (isFileLoggingEnabled()) { return new FileLogger(); } else { return new ConsoleLogger(); } } // helper method, check if FileLogging is ON // if so, log message to a file else print it to console. private boolean isFileLoggingEnabled() { Properties p = new Properties(); try { p.load(ClassLoader.getSystemResourceAsStream("logger.properties")); String fileLoggingValue = p.getProperty("FileLogging"); if (fileLoggingValue.equalsIgnoreCase("ON") == true) return true; else return false; } catch (IOException e) { return false; } } } class FactoryMethodPattern { public static void main(String args[]) { Factory f = new Factory(); Logger msgLogger = f.getLogger(); msgLogger.logMessage("Sample log message" + "\n"); } }
Above piece of code just demonstrates how factory method design pattern is developed. Choosing appropriate class from a hierarchy may be complex if different classes in the class hierarchy need to be instantiated in diverse manners.
In this tutorial we presented factory method design pattern. Please do write us if you have any suggestion/comment or come across any error on this page. Thanks for reading!
Share this page on WhatsApp