This article shows how to apply a pattern to
an everyday problem. For more in-depth information
concerning the factory pattern, look
here (wikipedia). Even more pattern information can be read
GoF-book (the Gang of Four), the "pattern bible". When discussing
further reading, the interested reader can also
continue by looking at the
abstract factory pattern.
What is a pattern? It is what
lies beyond the code. Try to look above the code
at the structure of interconnected instances of
classes. This is the pattern. I like to see it
as the next level of abstraction.
We want to be able to save and load our data,
the document, our settings, whatever. The file
formats may differ and we may be able to load
from ten formats and save to seven formats of
which only five can be read from. While doing this
we are interested in finding a nice object orientation
to get a good structure.
I restrict this example to loading from files,
but this approach can be used to handle different
sources of data, etc.
First, let us declare a document class. This
class acts as a data container but also
hold methods to handle user interaction and
such. Through out this text I will use C++ as
implementation language, but look at the code
as pseudo code. The concepts can be implemented in
any other language - but it is nice if it
supports object orientation.
setValue( int );
This class is only an example. All that it does
is that it holds a value. It also has a method
called process() that does something
to the value.
Now for the problem to be solved. We want to
be able to save and load the Data class in a number
of different formats, or encodings. Let us start
with the loading.
Which Pattern to Use
There are two major factory patterns (there are
others too, and even more
creational patterns): The Factory Pattern and
the Abstract Factory Pattern.
The factory pattern works as this. The creator,
i.e. the function wanting to create an instance of the
worker object (the object performing a task) class, calls
the factory method which in turn creates the requested
instance and returns it.
The abstract factory pattern defines an abstract base
class (i.e. an
interface) with a number of factory methods. A famous
example is the cross platform user interface framework
with an abstract factory that can create buttons, labels,
text boxes, etc. The abstract base factory is then inherited
for each platform implementation where the factory methods
How is the abstract factory used then? The creator
creates an instance of the inherited factories but only uses
the abstract factory interface defined by the abstract base
class. It then uses the factories of the instance to build
We will use the factory pattern. Why? Since
we cannot save in all formats and cannot load
from all formats, we need two factory methods:
one for loading and one for saving. If
we would have been able to load and save in every
format an abstract factory pattern would have
been and option - but the factory pattern would
not have been excluded.
We begin by defining an interface class (i.e.
a class without any non-virtual methods and no data) for our worker class.
virtual Data *load( char *fileName );
This provides us with an interface to a data
loader. All it has is a method called Load
that load the information and returns a pointer
to a Data (or null if it fails).
Now we can implement a number of loaders:
class BigEndianLoader : public DataLoader;
class LittleEndianLoader : public DataLoader;
class UniCodeTextLoader : public DataLoader;
class CompressedLoader : public DataLoader;
I do not bother implementing these loaders,
but I can summarize what they must do. First
they open the file and read the data from the
stream. Then, if the first stage succeded, they
create an instance of the Data class
and use the public interface to set the state
of the object according to the loaded data.
Finally, they return a pointer to the newly
created object. Of course they must also close
the file, clean up any dynamically allocated
memory, etc. But that is details that this text
is not concerned with.
To handle these loaders we need a loaded
factory class. The reason to creating a class
and not a single function is that a class can
handle loading of plug-ins and such in a real
application. This class could benefit from
being implemented as a
singleton, or the information concerning,
for example, plug-ins could be allocated
statically. This is up to the implementor.
DataLoader *createLoader( char *fileType );
Why is not an enumerated type used for the
file types? Since the factory can handle plug-ins
or any other technique to handle unknown file
formats the number of managed formats are not
known. One way to handle this is to add a method
that returns a list of all types that can be
handled. For example, when showing a file loading
dialog one could extract the accepted file formats
from the factory and the feed the factory the
user's choice from the dialog.
So, how is this used? Let me show you a small
dl = f.createLoader( "type" );
if( !dl )
throw( someException() );
d = dl->load( "/home/joe/file.ext" );
Nice and easy. First, we try to find a loader for
the file type with the extension "ext", then
we load the file using the loader. If the file format
is unknown we react at the error by throwing an
There may arise issues over how memory allocation
and such is handled. This is a language dependant
(non-pattern) issue. In the C++ recommentation I
would choose to make the factories work as the
new keyword, i.e. the calling function is
responsible for deleting it.
So, I was writing about loading and saving. What
about the saving you may ask? Just write your own
DataSaver interface class, a
DataSaverFactory and they some data
savers. It works the same way, just that the method
of the DataSaver interface aught to be
save( const Data& ) instead of load.
There are many patterns available that make it
easy to design powerful and structured solutions.
By learning patterns and applying them to everyday
problems slick solutions are achieved without
breaking a sweat.
The example above is small, but not naïve. It
utilizes a pattern to implement a common problem.
As discussed in the text several patterns may
apply to one solution, this is where the
developer's experience comes into work. Any
experienced developer working with object
orientation should know patterns; How to
use them and when.
For the programming reader without any
experience of object orientation I hope that
this article gives a glimpse into what the
abstractions that object orientation provides
can be used for. Remember that patterns are
not bound to one particular programming
language but represents a concept that
can be implemented in any environment.