Introduction
An object factory mechanism is needed whenever polymorphic objects need to be created whose concrete type can only be determined at runtime. The most straightforward implementation of an object factory would be something like:
Fruit Create( string strType )
{
switch( strType )
{
case "Apple":
return new Apple();
case "Orange":
return new Orange();
}
}
But this implementation has a drawback. Whenever you add a new object type, the factory has to be updated. In C++, there are some well known generic solutions to this problem. For more information about this, I refer to Andrei Alexandrescu – Modern C++ Design. Now that C# also supports generics, I wondered if a similar solution would be possible in this language.
The code
The heart of the factory is the SortedList
that holds a delegate for each registered object. The Register
function creates these delegates by instantiating a generic member function for the object that is supplied as the type argument. To create a registered object, the Create
function just looks up the appropriate delegate and executes it.
using System.Collections.Generic;
public struct Factory < KeyType, GeneralProduct >
{
public void> Register< SpecificProduct >(KeyType key)
where SpecificProduct : GeneralProduct, new()
{
if( m_mapProducts == null )
{
m_mapProducts = new SortedList< KeyType, CreateFunctor >();
}
CreateFunctor createFunctor = Creator<SpecificProduct>;
m_mapProducts.Add(key, createFunctor);
}
public GeneralProduct Create( KeyType key )
{
CreateFunctor createFunctor = m_mapProducts[ key ];
return createFunctor();
}
private GeneralProduct Creator < SpecificProduct >()
where SpecificProduct : GeneralProduct, new()
{
return new SpecificProduct();
}
private delegate GeneralProduct CreateFunctor();
private SortedList<KeyType, CreateFunctor> m_mapProducts;
}
Using the code
Here is an example on how to use the generic object factory:
class Fruit
{
}
class Apple : Fruit
{
}
class Orange : Fruit
{
}
class TestClass
{
static void Main(string[] args)
{
General.Factory< string, Fruit > factory;
factory.Register< Apple >( "Apple" );
factory.Register< Orange>( "Orange" );
Fruit fruit1 = factory.Create("Apple");
Fruit fruit2 = factory.Create("Orange");
}
}
The example shows two objects, both derived from the same Fruit
base class. Both the base class and the identifier type need to be supplied as type arguments when instantiating the factory. In this example, I use a string
as the identifier for the registering objects, in general an enum
type would be more appropriate.
History
- Initial version - 2/12/2006.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.