View RSS Feed

My Java Tips

Factory Methods

Rate this Entry
by , 06-02-2011 at 07:11 PM (2118 Views)
This post lists some facts about factory methods.

Factory methods are static methods that return an instance of the native class. Some examples from JDK include :

  • LogManager.getLogManager
  • Pattern.compile
  • Collections.unmodifiableCollection
  • Collections.synchronizeCollection
  • Calendar.getInstance


Factory methods do not have names like constructors and do not need to create a new object upon each invocation. Objects can be cached and reused, if necessary. Factory methods can return a subtype of their return type. They can return an object whose implementation class is unknown to the caller. It is a very valuable and widely used feature in many frameworks which use interfaces as the return type of static factory methods.

Common names for factory methods include getInstance and valueOf.

Knowing and using design patterns is very important when working in professional environment. In the next few posts, I’ll be writing about Factory methods.

Simply stating, Factory method is a method that instantiates objects. It is quite similar to a factory and its job is to create objects. Let me present an example to clarify things. We have an interface named Trace with 2 implementations.

Interface Trace is presented below with 3 method signatures.

Java Code:
public interface Trace {

      public void setDebug( boolean debug );
      public void debug( String message );
      public void error( String message );
}
There are 2 implementations of Trace. One writes the messages to the command line and the another writes them to a file.

Class diagram of discussed model is presented:

Name:  traceimpl.png
Views: 213
Size:  5.9 KB

File based implementation is presented below. Its overrides all the required methods.

Java Code:
public class FileTrace implements Trace {
          
      private java.io.PrintWriter pw;
      private boolean debug;
      public FileTrace() throws java.io.IOException {
            // a real FileTrace would need to obtain the filename somewhere
            // for the example I'll hardcode it
            pw = new java.io.PrintWriter( new java.io.FileWriter( "c:\trace.log" ) );
      }
      public void setDebug( boolean debug ) {
            this.debug = debug;
      }
      public void debug( String message ) {
            if( debug ) {  // only print if debug is true
                  pw.println( "DEBUG: " + message );
                  pw.flush();
            }
      }
      public void error( String message ) {
            // always print out errors
            pw.println( "ERROR: " + message );
            pw.flush();
      }
}
To use FileTrace, we will do the following:

Java Code:
…
FileTrace log = new SystemTrace();
…
log.debug( "entering log" );
…
Implementation that prints messages on command prompt is presented in this post.

Java Code:
public class SystemTrace implements Trace {
      private boolean debug;
      public void setDebug( boolean debug ) {
            this.debug = debug;
      }
      public void debug( String message ) {
            if( debug ) {  // only print if debug is true
                  System.out.println( "DEBUG: " + message );
            }
      }
      public void error( String message ) {
            // always print out errors
            System.out.println( "ERROR: " + message );
      }
}
To use SystemTrace, we will do the following:

Java Code:
…
SystemTrace log = new SystemTrace();
…
log.debug( "entering log" );
…
This approach has drawbacks discussed below.

We are simply creating the object of the implementing class and using it where needed. It looks simple but has drawbacks. If we want to change the Trace implementation that the program uses, we need to edit each class that instantiates a Trace implementation. If a lot of classes are using Trace, it might take a lot of work to make the change.

Our aim should be to avoid altering the classes as much as possible. Factory methods helps us in this. A factory method defines how our classes obtain Trace implementation instances. For instance:

Java Code:
public class TraceFactory {
      public static Trace getTrace() {
            return new SystemTrace();
      }
}
In the example presented in the last post, getTrace() is a factory method. Whenever you want to obtain a reference to a Trace, you can simply call TraceFactory.getTrace().

For instance:

Java Code:
…
Trace log = new TraceFactory.getTrace();
...
log.debug( "entering log" );
...
Surely if you use a factory method to obtain an instance, it will save a lot of work later. In the presented example, TraceFactory returns SystemTrace instances. Lets assume after a while you need to change the used implementation to FileTrace. Since you are using factory method to obtain the instance, you simple need to alter the factory method that thats it. You do not need to make changes in every class that uses Trace.

Factory methods are also useful when you're not sure what concrete implementation of a class to instantiate. You can leave those details to the factory method.

Java Code:
public class TraceFactory {
      public static Trace getTrace() {
            try {
                  return new FileTrace();
            } catch ( java.io.IOException ex ) {
                  Trace t = new SystemTrace();
                  t.error( "could not instantiate FileTrace: " + ex.getMessage() );
                  return t;
            }
      }
}
In the presented example, our program didn't know whether to create FileTrace or SystemTrace instances. Instead, you can program your objects to simply use Trace and leave the instantiation of the concrete implementation to a factory method.

I hope this was useful.

Submit "Factory Methods" to Facebook Submit "Factory Methods" to Digg Submit "Factory Methods" to del.icio.us Submit "Factory Methods" to StumbleUpon Submit "Factory Methods" to Google

Comments