Factory pattern with generics
This post supposes that you have some knowledge about generics and what the Factory pattern are.
The Factory pattern is a powerful creational pattern; it provides a way to instantiate classes dynamically at run time (For more info http://www.dofactory.com/Patterns/Patterns.aspx).
Generics opens a lot of new ways in order to implement many of the GOF patterns. But I was looking for an implementation of the factory pattern using generics and I didn't find something that solve my case.
If we need to create a factory class that supports only one kind of object obviously the implementation of the factory using generics is easy.
public
interface
IFactory<T>
{
T
Create();
}
public
class Factory<T> :
IFactory<T> where T :
new()
{
public T Create()
{
return
new T();
}
}
But as Hugo Troche explain in this article
“Generics change the basic implementation dynamic of factories. With factories the system defines the type of an object at run time. With generics the compiler has to be able to figure out the type of all objects at compile time”
The problem is when we need to create (as the pattern
say) a different object depending on a key.
Let me explain a bit more what I’m going to try to solve. Suppose the common use case for a factory pattern:
public
interface ICar
{
string Name {
get; }
}
public
class Ford : ICar
{
#region
ICar Members
public
string Name
{
get {
return "Ford"; }
}
#endregion
}
public
class Fiat : ICar
{
#region
ICar Members
public
string Name
{
get {
return "Fiat"; }
}
#endregion
}
Hugo in his article found a solution using a combination
of the Factory and a Chain of Responsibility patterns. It
is a cool solution but you should change your classes
definitions in order to implement the Chain of
responsibility.
I was looking a solution for this use case with the following characteristics:
- The factory should have a strong typed method that returns a Car. (ie Car Create(string name) )
- The factory never rise an InvalidCastException
- It should be implemented using Generics in order to use it for other cases.
So I started defining the interface for the factory
public
interface
IFactory<K, T> where K :
IComparable
{
T
Create();
}
After I defined a helper interface for the items in the
factory
public
interface
IFactoryElement
{
object New();
}
An implementation of the IFactoryElement
public
class
FactoryElement<T> :
IFactoryElement
where T :
new()
{
public
object New()
{
return
new T();
}
}
As you can see the New method returns an object and not
T. If it returns T we are defining that the Create method
of the factory will return always something of type T.
Now the factory
public
class
Factory<K, T> :
IFactory<K, T> where K :
IComparable
{
///
Elements that can be created
Dictionary<K,
IFactoryElement> elements = new
Dictionary<K,
IFactoryElement>();
/// <summary>
/// Add a new creatable kind of object to the factory. Here is the key with the beauty of the constrains in generics. Look that we are saying that V should be derived of T and it must be creatable
/// </summary>
public
void Add<V>(K key)
where V : T,
new()
{
elements.Add(key, new FactoryElement<V>());
}
public T Create(K
key)
{
if
(elements.ContainsKey(key))
{
return (T)
elements[key].New();
}
throw
new
ArgumentException();
}
}
Note that the Create method never raise an
InvalidCastException
because elements[key] is going to return something of type
V, and T is the base class of V !!
So for the use case of the cars I can use my generic
factory in this way:
public
class
CarFactory
{
Factory<string, ICar>
internalFactory = new
Factory<string,
ICar>();
public
class CarFactory()
{
internalFactory.Add<Fiat>("fiat");
internalFactory.Add<Ford>("ford");
}
public
ICar
Create(string
carType)
{
return
internalFactory.Create(carType);
}
}
I could use directly the factory without this class, the only issue is that it has the Add method as public.
Comments in order to improve this implementation are
welcome !!