![]() | |
|
The Factory Method design pattern is a way to encapsulate object creation. Without a Factory Method, you
would simply call the class's constructor directly: Foo x = new Foo()
. With this pattern, you would
instead call the factory method: Foo x = Foo.create()
. The constructors are marked private
,
so they cannot be called except from inside the class, and the Factory Method is marked as static
so
that it can be called without first having an object.
Consider the following interface:
public interface Logger { // Write out a debug message public void debug(String msg); // Write out an error message public void error(String msg); }
Suppose that you have written two implementations. One implementation writes the messages out to the standard console, while another writes them to a file:
public class ConsoleLogger implements Logger { ConsoleLogger() {} // Not accessible from other packages ! public void debug(String msg) { out.println("DEBUG: " + msg); } public void error( String msg) { out.println("ERROR: " + msg); } }
public class FileLogger implements Logger { private PrintWriter pw; FileLogger() throws IOException { // Not accessible from other packages ! // throws java.io.FileNotFoundException if the file does not exist pw = new PrintWriter(new FileWriter("/tmp/logger.log" ) ); } public void debug(String msg) { pw.println("DEBUG: " + msg); pw.flush(); } public void error(String msg) { pw.println("ERROR: " + msg); pw.flush(); } }
Using a Factory Method to obtain an instance can save you a lot of work later. 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 Logger
:
public class LoggerFactory {
private static Logger l = null;
public static Logger getLogger() {
if (l == null) {
try {
l = new FileLogger(); // Can fail if log file does not exist
} catch (IOException e) {
l = new ConsoleLogger();
}
}
return l;
}
}
Client code will look like:
public class LoggerTest { public static void main(String[] args) { LoggerFactory.getLogger().debug("Test debug"); LoggerFactory.getLogger().error("Test error"); } }
There are a few advantages to this pattern:
The Factory can choose from many subclasses (or implementers of an interface) and return that.
This way the caller can specify the behavior desired via parameters, without having to know or understand a potentially complex class hierarchy.
For example, some of the methods in java.sql.DriverManager
are Factory Methods that return implementation instances by their
interface type. By keeping the actual concrete type hidden, the factory has the flexibility to provide any implementing type, even a different one
from time to time, without damage to client code. This is part of what is sometimes called, "programming to the interface" or "programming to the
type", a best practice of defining behaviors at the interface level and generally hiding the concrete classes involved.
The conn
is actually some DB vendor's class implementing java.sql.Connection
interface:
String url = "jdbc:some_jdbc_vendor:other_data"; Connection conn = DriverManager.getConnection(url);
Controlling access to a limited resource such as connections. This a way to implement pools of reusable objects - instead of building, using, and tearing down an object, if the construction and destruction are expensive processes it might make more sense to build them once and recycle them.
The Factory Method can return an existing, unused instantiated object if it has one, or construct one if the object count is below some lower
threshold, or throw an exception or return null
if it is above the upper threshold.
Factory Methods have names, unlike constructors, which can clarify code.
Factory Method is useful when working with hierarchies of related classes, a good example of this would be a GUI toolkit.
Today factories have largely been brushed aside in favor of using Dependency Injection (DI) because they require a lot of boiler-plate code that turns out to be a little hard to maintain itself. Dependency Injection is basically equivalent to factories but allows you to specify how your objects get wired together declaratively (through XML configuration or annotations).
Usage of factory Design Patterns in Java Se and Java EE
Abstract factory (recognizeable by creational methods returning an abstract/interface type):
java.util.Calendar#getInstance()
java.util.Arrays#asList()
java.util.ResourceBundle#getBundle()
java.net.URL#openConnection()
java.sql.DriverManager#getConnection()
java.sql.Connection#createStatement()
java.sql.Statement#executeQuery()
java.text.NumberFormat#getInstance()
Factory method (recognizeable by creational methods returning a concrete type)
java.lang.Object#toString()
(overrideable in all subclasses)
java.lang.Class#newInstance()
java.lang.Integer#valueOf(String)
(also on Boolean
, Byte
,
Character
, Short
, Long
, Float
, and Double
)
java.lang.Class#forName()
Class NumberFormat
NumberFormat
is the abstract base class for all number formats. This class provides the interface for formatting
and parsing numbers. NumberFormat
also provides methods for determining which locales have number formats, and what
their names are.
NumberFormat
helps you to format and parse numbers for any locale. Your code can be completely independent of the
locale conventions for decimal points, thousands-separators, or even the particular decimal digits used, or whether the
number format is even decimal.
To format a number for the current Locale
, use one of the factory class methods:
NumberFormat nf = NumberFormat.getInstance(); String myString = nf.format(myNumber);
To format a number for a different Locale
, specify it in the call to getInstance(...)
:
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
The NumberFormat
class has many factory methods:
public static final NumberFormat getInstance() public static NumberFormat getInstance(Locale inLocale) public static final NumberFormat getNumberInstance() public static NumberFormat getNumberInstance(Locale inLocale) public static final NumberFormat getIntegerInstance() public static NumberFormat getIntegerInstance(Locale inLocale) public static final NumberFormat getCurrencyInstance() public static NumberFormat getCurrencyInstance(Locale inLocale) public static final NumberFormat getPercentInstance() public static NumberFormat getPercentInstance(Locale inLocale)
![]() ![]() ![]() |