Background
Sitting in the dark feeding a new baby at 3am gives a person lots of time to ponder. So it was that I was reflecting on the factory tip I had posted a few weeks ago: http://www.codeproject.com/Tips/1020264/Factory-Pattern-for-Derived-Classes.
I wondered if a basic generic factory model could be designed in such a way as to do away with the need for specific type implementations completely. One factory to rule them all...
Using the code
The factory is a singleton
with a generic type property (the interface
you are generating in your concrete factory) and a single public
static Create
method.
Objects created by the factory are required to implement the IFactoryObject<T>
interface. this defines two methods. FactoryId
, which provides the key for the factory type lookup dictionary,and FactoryCreate
, which returns a new T
object.
public interface IFactoryObject<T>
{
Enum FactoryId { get; }
T FactoryCreate(object[] args);
}
The singleton Factory
class is created as you might expect, but instead of an Instance property, the private instance
is verified and instantiated in the Create
method. When first called the singleton is initialized, reflecting all types derived from T
and using their FactoryId
property to populate a lookup
dictionary.
public class Factory<T> where T : IFactoryObject<T>
{
private static Factory<T> _instance;
private Dictionary<Enum, IFactoryObject<T>> _lookup = new Dictionary<Enum, IFactoryObject<T>>();
private Factory() { }
public static T Create(Enum id, params object[] args)
{
if (_instance == null) CreateInstance();
return _instance.CreateProduct(id, args);
}
private static void CreateInstance()
{
_instance = new Factory<T>();
_instance.Initialize();
}
private void Initialize()
{
Type t = typeof(T);
if (!t.IsInterface) return;
var assembly = Assembly.GetExecutingAssembly();
foreach (var type in assembly.GetTypes())
{
if (!type.IsClass || !t.IsAssignableFrom(type)) continue;
Register(type);
}
}
private void Register(Type type)
{
var inst = System.Activator.CreateInstance(type) as IFactoryObject<T>;
_lookup.Add(inst.FactoryId, inst);
}
Once initialized, the Create
method will lookup your type and call IFactoryObject<T>.FactoryCreate
to instantiate and return a new T
object for you.
public static T Create(Enum id, params object[] args)
{
if (_instance == null) CreateInstance();
return _instance.CreateProduct(id, args);
}
private T CreateProduct(Enum id, object[] args)
{
return _lookup[id].FactoryCreate(args);
}
Factory objects are easy to create and there is no need to maintain any kind of lookup for your factory or type.
public interface IPerson : IFactoryObject<IPerson>
{
string PersonMethod1();
string PersonMethod2();
}
public class PersonA : IPerson
{
public Enum FactoryId { get { return PersonType.PersonTypeA; } }
public virtual IPerson FactoryCreate(object[] args)
{
return new PersonA();
}
public string PersonMethod1()
{
return "Person A Method 1";
}
public string PersonMethod2()
{
return "Person A Method 2";
}
}
Better still, there is absolutely no need to create, define, set up or otherwise waste time with any individual factories. Using the Create method with an IFactoryObject
Type will create a new one for you!
IPerson personA = Factory<IPerson>.Create(PersonType.PersonTypeA);
Points of Interest
I made a Factory
that takes an Enum
and returns an Interface
. That doesn't mean you have to. With some thought about how best to minimize runtime errors, you could use anything from object
to complex types as your identifier, so long as it can be used as a Dictionary Key
property. You can also return any class deriving from IFactoryObject<T>
.
I just like Enums and Interfaces.