Introduction
This short article just shows the evolution of my implementation of the Factory pattern in C#.
Since Factory pattern is so frequently used, this article describes better ways to implement it in C#.
I could go and show some UML to describe pattern but lets go straight to the code, people unfamiliar with this pattern can Google it.
Using the code
Below diagram shows example concrete class that our factory could build for us, they all implement same interface.
I am going to use an enum ConcreteType as key to map concrete types, in your implementation
you can use whatever better fits you.
Factory Version 1
In this version work is done
by a switch
, it can be implemented even in Framework 1.0.
using System;
namespace BetterFactories
{
public class FactoryV1
{
public IMyInterface Get(ConcreteType concreteType)
{
switch (concreteType)
{
case ConcreteType.Concrete1:
return new MyConcreteClass1();
case ConcreteType.Concrete2:
return new MyConcreteClass2();
case ConcreteType.Concrete3:
return new MyConcreteClass3();
default:
throw new NotImplementedException();
}
}
}
}
Factory Version 2
In this version we have a Dictionary
were we keep mappings for our concrete types.
Since now we are using generics we need Framework 2.0 or above.
using System;
using System.Collections.Generic;
namespace BetterFactories
{
public class FactoryV2
{
public FactoryV2()
{
_Mappings = new Dictionary<ConcreteType,Type>(3);
_Mappings.Add(ConcreteType.Concrete1, typeof(MyConcreteClass1));
_Mappings.Add(ConcreteType.Concrete2, typeof(MyConcreteClass2));
_Mappings.Add(ConcreteType.Concrete3, typeof(MyConcreteClass3));
}
public IMyInterface Get(ConcreteType concreteType)
{
Type type;
if(_Mappings.TryGetValue(concreteType, out type))
{
return Activator.CreateInstance(type) as IMyInterface;
}
else
throw new NotImplementedException();
}
readonly Dictionary<ConcreteType, Type> _Mappings;
}
}
After doing a benchmark to Activator.CreateInstance
class I realized there was a performance hit here.
Factory Version 3
Here we have a similar approach but now our Dictionary
points to a
Func<T>
which improves performance and avoids casting.
Since this uses Func<T>
we need Framework 3.5 or above.
using System;
using System.Collections.Generic;
namespace BetterFactories
{
public class FactoryV3
{
public FactoryV3()
{
_Mappings = new Dictionary<ConcreteType,Func<IMyInterface>>(3);
_Mappings.Add(ConcreteType.Concrete1, () => new MyConcreteClass1());
_Mappings.Add(ConcreteType.Concrete2, () => new MyConcreteClass2());
_Mappings.Add(ConcreteType.Concrete3, () => new MyConcreteClass3());
}
public IMyInterface Get(ConcreteType concreteType)
{
Func<IMyInterface> func;
if (_Mappings.TryGetValue(concreteType, out func))
{
return func();
}
else
throw new NotImplementedException();
}
readonly Dictionary<ConcreteType, Func<IMyInterface>> _Mappings;
}
}
Points of Interest
After years of implementing this pattern it has changed several times but these three versions encapsulate the milestones.
If you have suggestions to improve it please bring up your comments.
Project attached contains all source code created in VS2008.