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 !!