Q: While going through " Polymorphism in its purest form ," I saw the unfamiliar term factory method. Could you please describe what a factory method is and explain how I can use it?
A: Let's consider an example.
Every program needs a way to report errors. Consider the following interface:
Listing 1
public interface Trace { // turn on and off debugging public void setDebug( boolean debug ); // write out a debug message public void debug( String message ); // write out an error message public void error( String message ); }
Suppose that you've written two implementations. One implementation (Listing 2) writes the messages out to the command line, while another (Listing 3) writes them to a file.
Listing 2
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(); } }
Listing 3
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 either of these classes, you would need to do the following:
Listing 4
//... some code ... SystemTrace log = new SystemTrace(); //... code ... log.debug( "entering loog" ); // ... etc ...
Now if you want to change the Trace
implementation that your program uses, you'll need to edit each class that instantiates a Trace
implementation. Depending upon the number of classes that use Trace
, it might take a lot of work for you to make the change. Plus, you want to avoid altering your classes as much as possible.
A factory method lets us be a lot smarter about how our classes obtain Trace
implementation instances:
Listing 5
public class TraceFactory { public static Trace getTrace() { return new SystemTrace(); } }
getTrace()
is a factory method. Now, whenever you want to obtain a reference to a Trace
, you can simply call TraceFactory.getTrace()
:
Listing 6
//... some code ... Trace log = new TraceFactory.getTrace(); //... code ... log.debug( "entering loog" ); // ... etc ...
Using a factory method to obtain an instance can save you a lot of work later. In the code above, TraceFactory
returns SystemTrace
instances. Imagine again that your requirements change and that you need to write your messages out to a file. However, if you use a factory method to obtain your instance, you need to make only one change in one class in order to meet the new requirements. You do not need to make changes in every class that uses Trace
. Instead you can simply redefine getTrace()
:
Listing 7
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; } } }
Further, factory methods prove useful when you're not sure what concrete implementation of a class to instantiate. Instead, you can leave those details to the factory method.
In the above examples your 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.
Learn more about this topic
- The first stop for all your pattern needs can be found in the famous Gang of Four bookDesign Patterns, Eric Gamma, Richard Helm, Ralph Johnson, John Vlissides (Addison-Wesley, 1995)
http://www.amazon.com/exec/obidos/ASIN/0201633612/javaworld - Want more? See the Java Q&A index for the full Q&A catalog
http://www.javaworld.com/javaworld/javaqa/javaqa-index.html - For over 100 insightful Java tips from some of the best minds in the business, visit JavaWorld's Java Tips index
http://www.javaworld.com/javatips/jw-javatips.index.html - For more articles geared toward new Java programmers, visit the Intro Level section of JavaWorld's Topical Index
http://www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html - Speak out in the Java Beginner discussion
http://www.itworld.com/jump/jw-javaqa/forums.itworld.com/webx?14@@.ee6b804/1195!skip=1125 - Receive weekly Java programming tips by subscribing to our free Java Tutor email newsletter
http://reg.itworld.com/cgi-bin/subcontent12.cgi