In this post I’ll be looking at
the factory pattern. I’ll start off by looking at how the factory pattern is
commonly used and then I’ll take a look at the strict GoF (Gang of Four)
definition which is a little different and to be honest not as well known. The
factory pattern is all about encapsulating object creation logic into a single
object that can be used by other parts of your code.
I’ll start off with an example
that describes a scenario where the factory pattern could be put to work. Imagine
we have an application that takes data from multiple sources and converts that
data into a common data standard. We’d probably use a data adapter of some
sorts to convert the incoming data to our common data standard. To begin with
were going to receive data in CSV format so
our code for creating a data adapter object might look something like this.
DataAdapter csvAdapter = new CsvDataAdapter();
Imagine requirements change and
we’re told that we also have to handle XML data from another source. So we set
to work building an XML data adapter and then create that object as follows.
DataAdapter xmlAdapter = new XMLDataAdapter();
Because we’ve got two different
types of data adapter we’ll need some sort of conditional logic in our
application that decides which data adapter to use. This logic might look something
like the following.
// default to XML data adapter
if (adapterType_i.equals("csv"))
{
return new CsvDataAdapter();
}
else
{
return new XmlDataAdapter();
}
It’s likely that we’ll have to
decide which data adapter we need at a number of different points in our
application. Rather than duplicate this
logic every time we need to create an adapter we’ll put this code into a method
that it can be reused. It’s likely that in the future our application will need
to support new data formats so this logic will need to be extended. To ensure
our code is easier to maintain we need to encapsulate the parts that are likely
to change the most. In this case that’s the object creation code so using the
factory pattern to encapsulate this code away from the rest of our logic makes
sense.
Creating the Factory
We’ll start by creating the actual
factory class itself - the factory will simply encapsulate the logic we’ve
already defined.
public class DataAdapterFactory
{
protected String adapterType_i;
public DataAdapterFactory(String adapterType_p)
{
adapterType_i = adapterType_p;
}
public DataAdapter createDataAdapter()
{
// default to XML data adapter
if (adapterType_i.equals("csv"))
{
return new CsvDataAdapter();
}
else
{
return new XmlDataAdapter();
}
}
}
The factory objects constructor
takes a single adapterType parameter which it uses to decide what type of
DataAdapter to create and return to the client. You’ll notice that the return
type of the createDataAdapter method is DataAdapter, even though the method can
return either a CsvDataAdapter or an XmlDataAdapter object. The code is exhibits polymorphic behaviour
as it allows calling code to use the adapters in the same way regardless of the
actual implementation. For example, if a client is returned an XmlDataAdapter,
it should be able to call the same functions on that object as if it were any
other type of adapter.
In our case we’ll implement this polymorphic
behaviour by ensuring that all objects returned by the factory extend our
abstract DataAdapter class. Extending classes will be forced to implement the
convertData method and by doing so provide a specific DataAdapter
implementation.
Creating the concrete adapter classes
So what do the concrete adapter implementations look like? We’ll start off by defining the CsvDataAdapter as follows.
public abstract class DataAdapter
{
public DataAdapter()
{
}
/* method template that extending classes are forced to
implement */
public abstract String convertData(String inputData_p);
}
Creating the concrete adapter classes
So what do the concrete adapter implementations look like? We’ll start off by defining the CsvDataAdapter as follows.
public class CsvDataAdapter extends DataAdapter
{
public CsvDataAdapter()
{
}
public String convertData(String inputData_p)
{
// some data adapter code could go here to convert CSV to common data standard
return "csv data[" + inputData_p + "] " + "converted to common data standard";
}
}
This class extends abstract DataAdapter
and overrides the mandatory convertData method. I’ll not be providing the csv transformation
code but the class above should be sufficient to show you how a DataAdapter
implementation class is structured.
public class XmlDataAdapter extends DataAdapter
{
public XmlDataAdapter()
{
}
public String convertData(String inputData_p)
{
// some data adapter code could go here to convert XML to common data standard
return "XML data[" + inputData_p + "] " + "converted to common data standard";
}
}
The relationship between the
abstract DataAdapter and its subclasses is shown below.
Testing our factory
Before we test our factory here is
a summary of what we’ve created so far.
- DataAdaptrerFactory class
- DataAdapter abstract class
- CsvDataAdapter concrete implementation class
- XmlDataAdapter concrete implementation class
Now let’s see the factory pattern
in action with a simple test harness.
public class TestFactoryPattern
{
public static void main (String[] args_p)
{
DataAdapterFactory adapterFactory;
DataAdapter dataAdapter;
String convertedData;
adapterFactory = new DataAdapterFactory("csv");
dataAdapter = adapterFactory.createDataAdapter();
convertedData = dataAdapter.convertData("some, simple, csv, data");
System.out.println(convertedData);
adapterFactory = new DataAdapterFactory("xml");
dataAdapter = adapterFactory.createDataAdapter();
convertedData = dataAdapter.convertData("<TestData>data</TestData>");
System.out.println(convertedData);
}
}
On line 10 we create a new factory
object passing in the adapter type. On line 11 we then use the factory’s
createDataAdapter method to get a reference to a new CsvDataAdapter object.
Note that this object is assigned to a DataAdapter variable - this is possible
because CsvDataAdapter is derived from the base type DataAdapter. On line 12 we invoke the
convertData method and see it print some csv specific output. Lines 16, 17 and 18 follow a
similar pattern with a new factory object being used to create an
XmlDataAdapter. Once again this object is assigned to its parent type
(DataAdapter) and when we invoke its convertData method we’ll see some XML
specific output.
This simple example shows how we
can use a factory class to create a variety of different object types. We’ve
encapsulated our object creation logic inside a dedicated class making it
easier to maintain than if it were scattered throughout our (hypothetical)
application.
GoF factory pattern
The pattern I described above is a
recognised and commonly used form of the factory pattern. However the formal GoF
definition of the factory pattern is slightly different and states.
‘The factory pattern should define
an interface for creating an object, but let subclasses decide which classes to
instantiate. Factory method lets a class defer instantiation to subclasses’.
The GoF definition of the factory
class allows greater flexibility by allowing you to define how factory methods
should be structured but leave it up to the sub classer to implement the actual
factory.
Creating an abstract factory
In order to allow subclasses to decide
which class to instantiate we’ll need to define the factory as an abstract class.
The abstract class is a specification for a factory and the actual implementation
is the responsibility of the developer that extends it.
Our factory specification is
defined with the abstract class below.
Creating a concrete factory
public abstract class AbstractDataAdapterFactory
{
public AbstractDataAdapterFactory()
{
}
/* our abstract method that subclassers will implement */
public abstract DataAdapter createDataAdapter(String adapterType_p);
}
Creating a concrete factory
Now that we have our specification
we need to create a factory implementation by extending the abstract class. Our
factory implementation will look similar to the factory created earlier except
that it will extend the specification defined by our abstract class. You’ll
notice that the factory returns the same types that were returned by our earlier
example. We could have created new DataAdapter implementations but for
convenience we’ll stick with the ones we defined in our earlier example (CsvDataAdapter,
XlDataAdapter).
Testing our GoF factory
Now let’s see the GoF factory
pattern in action with a simple test harness. You’ll notice that this test harness
is almost identical to the one used earlier, except that this time we create an
instance of our DataAdapterFactoryImpl class that extends the AbstractDataAdapterFactory.
public class TestGoFFactoryPattern
{
public static void main (String[] args_p)
{
AbstractDataAdapterFactory adapterFactory;
DataAdapter dataAdapter;
String convertedData;
adapterFactory = new DataAdapterFactoryImpl();
dataAdapter = adapterFactory.createDataAdapter("csv");
convertedData = dataAdapter.convertData("some, simple, csv, data");
System.out.println(convertedData);
adapterFactory = new DataAdapterFactoryImpl();
dataAdapter = adapterFactory.createDataAdapter("xml");
convertedData = dataAdapter.convertData("<TestData>data</TestData>");
System.out.println(convertedData);
}
}
On line 10 we create a new factory
implementation and assign it to an AbstractDataAdapterFactory reference. This
differs from the first example because we can now potentially have a number of
different types of factory, each of which could be assigned to a AbstractDataAdapterFactory
reference. The rest of this test class is almost identical to the test class
used in the first example.
Why use the GoF factory pattern?
At this point you may well be
asking why would I use the GoF factory pattern instead of the more traditional version
described in the first part of this post? In both examples we have a factory
object that encapsulates object creation logic and return objects that extend a
base type. Rather than have a single factory
class instantiate all our objects (like our first example), the GoF version
allows us to have one or more sub classes that handle object creation. This
allows greater flexibility because the abstract factory can be easily extended
to support new requirements rather than continually having to amend a single
factory class. The GoF factory pattern
is worth considering when there are a number of developers extending your
factory class and making substantial changes to the base implementation. In these
circumstances you would be better off defining a specification for the factory (abstract
class) and letting the developers who are overriding it take care of the
implementation.


