Also known as virtual constructor.
We need to decouple the behavior of an object from its creation. This might happen, for example, in a framework, where we can't anticipate the kind of objects we must create, but we can anticipate their behavior.
A factory method is a method that creates and returns new objects. A factory is a class containing one or more factory methods. In this context the types of objects created by the factory method are called products.
See:
An XML parser reads an XML document and parses it into a tree structure that conforms to the Document Object Model (DOM) specification. There are many XML parsers: Saxon and Xalan to name a few.
Java uses the Factory Method pattern to hide the type of parser used:
Here's some sample context code:
String xmlFile = "mydoc.xml";
// obtain parser factory:
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//obtain parser:
DocumentBuilder builder =
factory.newDocumentBuilder();
// parse an xml document into a DOM tree:
Document doc =
builder.parse(new File(xmlFile));
Java uses the Factory Method pattern to decouple the behavior of executing SQL queries from the type of database used:
One might argue that the sstatic getConnection method of the DriverManager class is also a factory method.
Here's some sample code:
String dbaseName =
dbasePrefix + dbase;
try {
Class.forName(driverName);
connection =
DriverManager.getConnection(
dbaseName, username,
password);
} catch (Exception e) { // dbase not
found?
System.err.println(
"can't connect to "
+ dbaseName + " because " + e);
connection =
DriverManager.getConnection(
dbaseName +
";create=true");
}
statement =
connection.createStatement();
In C++ template parameters can represent constructors as well as classes, so generic constructors can be used to delay decisions about the types of products to create:
template<typename Product>
class GenericFactory
{
public:
// generic constructor:
Product* makeProduct() { return new
Product(); }
};
In this case there is no need to introduce an abstract Product base class. Here is how a client creates a concrete product:
GenericFactory<ConcreteProductA> factory;
AbstractProduct* p = factory.makeProduct();
The same trick doesn't work in Java, however.
The Command Processor pattern can be enhanced by providing an abstract base class for all control listeners that uses a factory method to create commands to be forwarded to the command processor. Concrete listeners only need to implement the factory method.
abstract class AbstractCommandFactory implements ActionListener {
protected CommandProcessor cp;
public void actionPerformed(ActionEvent
ae) {
AbstractCommand cmmd =
makeCommand(ae.getLabel());
commandProcessor.execute(cmmd);
}
protected
AbstractCommand makeCommand(String label);
}
A generic listener for a view menu can use a factory method to create the needed view:
abstract class AbstractViewFactory implements ActionListener {
public void actionPerformed(ActionEvent
ae) {
AbstractView view = makeView(ae.getLabel());
view.setVisible(true);
}
protected
AbstractView makeView(String label);
}
In the Master-Slave pattern the master uses a factory method to create slaves that perform sub-tasks:
interface Slave extends Runnable {
}
public abstract class Master {
protected
abstract Slave makeSlave();
int slaveCount = 100;
Slave[] slaves = new Slave[slaveCount];
public void run() {
// create slaves:
for(int i = 0; i < slaveCount; i++) {
slaves[i] = makeSlave();
}
// start slaves:
for(int i = 0; i < slaveCount; i++) {
slaves[i].start();
}
// wait for slaves to die:
for(int i = 0; i < slaveCount; i++) {
try {
slaves[i].join();
} catch(InterruptedException
ie) {
System.err.println(ie.getMessage());
} finally {
System.out.println(slaves[i].getName() + " has died");
}
}
System.out.println("The master will now die
... ");
}
}
Creating and destroying (garbage collecting) products can be expensive. An interesting variation of a factory pulls unused products from a pool. A delete method returns products to the pool:
abstract class PoolingFactory implements AbstractFactory {
private Queue<AbstractProduct>
pool = new LinkedList<AbstractProduct>();
public AbstractProduct getProduct() {
if (pool.size() == 0) {
pool.add(makeProduct());
}
return pool.poll();
}
public void delete(AbstractProduct p) {
pool.offer(p);
}
}
In the Types as Objects Pattern InstanceType plays the role of Factory and Instance plays the role of Product.