Monday, September 25, 2006

Simple Generic Factory

Last time I presented you with simple factory pattern using dictionaries of methods and talked about Steven's (much more elegant and generic) implementation. I kept playing with Steven's code, whilst the dynamic code generation is pretty cool I kept thinking there was an easier way to accomplish the same thing; I finally came up with a much shorter version, here it is:

public static class SimpleStaticGenericFactory<TKey, TBaseType> where TBaseType : class {
public delegate TBaseType BaseTypeInvoker();
private static Dictionary<TKey, BaseTypeInvoker> methods =
new Dictionary<TKey, BaseTypeInvoker>();
public static void Add(TKey key, BaseTypeInvoker instantiatorMethod) {
if (!methods.ContainsKey(key))
methods.Add(key, instantiatorMethod);
}
public static void CreateInstance(TKey key) {
if (methods.ContainsKey(key))
methods[key]();
else //what would you like to do in this case?
throw new ArgumentException(string.Format("{0} not found", key));
}
}

that's it!, or if you prefer the non-static version:

public class SimpleGenericFactory<TKey, TBaseType> where TBaseType : class {
public delegate TBaseType BaseTypeInvoker();
private Dictionary<TKey, BaseTypeInvoker> methods =
new Dictionary<TKey, BaseTypeInvoker>();
public void Add(TKey key, BaseTypeInvoker instantiatorMethod) {
if (!methods.ContainsKey(key))
methods.Add(key, instantiatorMethod);
}
public void CreateInstance(TKey key) {
if (methods.ContainsKey(key))
methods[key]();
else //what would you like to do in this case?
throw new ArgumentException(string.Format("{0} not found", key));
}
}

We *don't really need* the CreateInstance method there, we could call the method directly if the dictionary was public, but it wouldn't be good to give them access to the dictionary. Using the reports from our last example, we could use it like:

SimpleStaticGenericFactory<string, BaseReport>.Add("report1", delegate() { return new Report1(); });
SimpleStaticGenericFactory<string, BaseReport>.Add("report2", delegate() { return new Report2(); });
SimpleStaticGenericFactory<string, BaseReport>.CreateInstance("report1");

or using the non-static version:

SimpleGenericFactory<string, BaseReport> reports1 = 
new SimpleGenericFactory<string, BaseReport>();
reports1.Add("report1", delegate() { return new Report1(); });
reports1.Add("report2", delegate() { return new Report2(); });
reports1.CreateInstance("report1");

nice and simple, I'll put an example together for a plug-in model using this factory


kick it on DotNetKicks.com

3 comments:

Steven said...

Nice. This solves the problem of creating objects that don't have a default constructor.

Anonymous said...

please can you give an implementation of this when the constructors of the created objects has multiple input data. Right now yours work well with a default constructors but what if you have lets say a string as input data to initialize the object??

Anonymous said...

How do I get a handle to my factory created object?
Should the create method not return an object of TBaseType instead of void?