Introduction
I hope to introduce a very basic implementation of the GoF design pattern. This is not intended to be the simplest possible implementation of the pattern ( a simpler one could certainly be derived from the Wikipedia entry on this topic http://en.wikipedia.org/wiki/Factory_method_pattern#Java). The intention is to attempt to demonstrate what the Factory Method Pattern is for, and give a simple implementation of it. This article will be relatively brief and hopefully clear for those trying to get to grips with this commonly mis-understood pattern.
Please note, this is a short, beginner's article. By beginner I mean beginner to this design pattern, it is necessary that the reader understand basic inheritance (especially interfaces) and visibility modifiers (principally internal
and public
).
Background - What is the Factory Method Pattern For?
I've seen the intent defined as "Given an interface for creating an object, but let subclasses decide which class to instantiate, then subclasses use factory methods. The factory method pattern lets a class defer instantiation to subclasses. " Which is more a statement of what it does and not very clear unless you know why it does it in my opinion. Let us start with first principles. In c-based languages (or at least those known to me at the time of writing) constructors:
- Can't be defined in an interface
- Must have their container type known to be called - both the type and the constructor must be visible to the calling code for
MyType foo = new <code>MyType
() to work
Let us suppose we want to write a logging framework, and we need to create a hypothetical
ILogger
interface. With our framework, we are to supply two
ILogger
implementations
FileLogger
and
SqlAndSql
to represent two different logging destinations. Now suppose that we do not want allow the "client" code to have access to the concrete classes for some reason. In this case, the constructor cannot be defined in the interface so using
ILogger
will not work, and we can't call
new
on these classes directly as we have deliberately made them unavailable. So what do we do? An answer is to use the Factory Method Pattern.
Creating the Pattern
The Logging classes - creating the problem to be overcome.
As described above we want to expose some logging functionality, step one is to create the ILogger
interface. For simplicity, I'm going to define our Interface as:
namespace LoggerClassLibrary
{
public interface ILogger
{
string Log();
}
}
Nothing too complicated there. Now we want to create the two implementations of the interface mentioned earlier SqlLogger
and DiskLogger
. For this article I will provde a fake, stub implementation to keep the code simple, and so avoid distracting from the actual work of the article. These classes are going to be:
namespace LoggerClassLibrary.ConcreteLoggers
{
internal class SqlLogger : ILogger
{
public string Log()
{
return "Logging to SQL";
}
}
}
and
namespace LoggerClassLibrary.ConcreteLoggers
{
internal class DiskLogger : ILogger
{
public string Log()
{
return "Logging to Disk";
}
}
}
Note that all of the above are being kept in a single assembly, and that I have declared the concrete classes as internal
. This results in any "client" code being unable to access the concrete implementations, these are not visible externally to the logger framework assembly (at least they can't be accessed without some jiggery pokery " /> ) . As the ILogger
interface is public
, not internal
, it is accessible from outside the dll (and therefore to the client) so I have set up the conditions for our problem: inaccessible concrete classes and, by extension, inaccessible constructors. How do we allow users of our logging framework to actually log?
Re-factoring towards the Factory Method Pattern
The first iteration towards a neat solution is to abstract the creation of the concrete logger classes into types which the client is allowed to access. This is a very simple step, we add the following to our framework assembly:
public class SqlLoggerCreator
{
public ILogger CreateLogger()
{
return new SqlLogger();
}
}
With a nearly identical class for the disk logger:
public class DiskLoggerCreator
{
public ILogger CreateLogger()
{
return new DiskLogger();
}
}
At this point, we could rest as we have put a sticking-plaster over the problem, the client could call this code. But we are more savvy than to settle for that " /> . The user of the logging framework is not going to want to write code along the lines of:
public void Log(DiskLoggerCreator creator)
{
ILogger logger = creator.CreateLogger();
Console.WriteLine(logger.Log());
}
public void Log(SqlLoggerCreator creator)
{
ILogger logger = creator.CreateLogger();
Console.WriteLine(logger.Log());
}
Not only is this duplicating work (bad), but if the additional concrete logger types are added, new methods like the above will need to be implemented by our user. As the methods being called are the same (I'll admit it - this was deliberate " /> ) we can make a further abstraction: we can make the creator classes implement a common interface so they become in our second iteration:
public interface ILoggerCreator
{
ILogger CreateLogger();
}
public class DiskLoggerCreator : ILoggerCreator
{
public ILogger CreateLogger()
{
return new DiskLogger();
}
}
public class SqlLoggerCreator : ILoggerCreator
{
public ILogger CreateLogger()
{
return new SqlLogger();
}
}
Now the client code becomes a much more manageable from our user's point of view (as well as having other benefits I will list later):
public void Log(ILoggerCreator creator)
{
ILogger logger = creator.CreateLogger();
Console.WriteLine(logger.Log());
}
This is now actually an implementation of the Factory Method Pattern (though we haven't broken it down yet it fulfils the intent described in the introduction) and we have also achieved our goals!
If you examine the sample code, the main program calls each logger in turn, but does not itself access the concrete classes, so we have succeeded in isolating those. In the course of this, we have also necessarily developed a way to create concrete class instances via creator classes which are defined in a base interface. In a sense we have created a "virtual constructor" - this is another name for this pattern.
Getting to the Factory Method Pattern from our Code
First we should re-cap what we've done:
- The concrete classes to be produced (
SqlLogger
and DiskLogger
) have a base interface ILogger
. - As the concrete classes are inaccessible we have ultimately defined an interface for a creator which defines a method that returns an
ILogger
. - For each concrete type, we define a concrete creator type (
SqlLoggerCreator
and DiskLoggerCreator
). These implement a common interface ILoggerCreator, which defines the method that does the work of returning the ILogger
Expressing this as UML (ignoring visibility on the concrete class side - it isn't that important now):
We can strip out the implementation specific stuff to produce one implementation of the pattern
This can be simplified even further to produce the diagram on the Wikipedia page (http://en.wikipedia.org/wiki/Factory_method_pattern) The biggest difference is really the "depends on" arrows linking the Creators with the classes these create . Additionally the UML diagram in the wikipedia entry only deals with one "product" type and therefore one creator class.
Note that we could replace all the Interfaces in this diagram with base classes or (a better option) abstract classes and it would still work. I have opted for interfaces as these provide the lowest coupling and complexity, they are also better for unit testing as I could mock my implementations, so I consider interfaces the best of the three inheritance options.
Other Benefits
Now we have the pattern constructed what else does it give us?
- We can put complicated set-up logic in the create methods. This is especially useful when the set-up logic does not naturally sit inside either the class being constructed or the class using it.
- Commonly used code in set-up can also be placed in the create methods - this removes duplication of code.
- We can now give the method constructing the class a more descriptive name - calling the constructor directly we are limited to type name.
- Following on from the design of the pattern - users of the produced interface can use types they are totally unaware of - they just need access to creators of these types.
- We are not limited to creating a new instance in the create methods - we could return a singleton instance for example.
Points of Interest
As described in the introduction, this is not the simplest implementation this also shows it is not the only implementation of this pattern, though it is a common one.
There seems to be a lot of confusion about this pattern. One common (formally incorrect) implementation is to do something like the following:
public class Factory
{
public IWhatever Create(int discriminator)
{
switch (discriminator)
{
case 1:
return new Whatever1();
break;
case 2:
return new Whatever2();
break;
}
}
}
Where the italics are the interface/types used (in our example ILogger
, DiskLogger
and SqlLogger
) and where discriminator can be any type use to define which type is emitted. Although it is commonly called a Factory method (probably more sensibly than the one in this article!) it is not an implementation of the Factory Method Pattern
As you use a Factory Method pattern in the real world, it quite often becomes inadequate over time. Commonly a different but closely related pattern the Abstract Factory Pattern is applied.
History
07/05/2013 - First Draft
08/05/2013 - Tidy up and clarification (hopefully)