Other Posts in Data Types

  1. Replacing List
  2. Factory Pattern using Generics in C#
  3. Vector Class and Events in .Net
  4. Binary Trees in C# using Generics
  5. Priority Queue in C#
  6. Cheap Trick for Fluent Interfaces
  7. Building an DI Container

Factory Pattern using Generics in C#

8/24/2009

I've been on a kick lately of just coding various things that I don't need right now but may need at some point in the future. One of those items is generic class to use in a factory pattern. For those of you who don't know what the factory pattern is, it's a creational pattern that creates objects based on an input without the caller necessarily knowing what type the object will be. Basically I need a class that can create other objects based on the input and sending back the object cast to an interface or base class (usually). It's fairly common in things like messaging systems, test driven development, frameworks, and the like.

Anyway, I was bored and thought a class that could handle any such instance like that would be fairly useful. So I set to work creating the class. And with the help of generics and the Func type, it turns out it's fairly easy:

   1: public class Factory<Key,T>
   2: {
   3:     #region Protected Variables
   4:  
   5:     /// <summary>
   6:     /// List of constructors/initializers
   7:     /// </summary>
   8:     protected Dictionary<Key, Func<T>> Constructors = new Dictionary<Key, Func<T>>();
   9:  
  10:     #endregion
  11:  
  12:     #region Public Functions
  13:  
  14:     /// <summary>
  15:     /// Registers an item
  16:     /// </summary>
  17:     /// <param name="Key">Item to register</param>
  18:     /// <param name="Result">The object to be returned</param>
  19:     public void Register(Key Key, T Result)
  20:     {
  21:         if (Constructors.ContainsKey(Key))
  22:             Constructors[Key] = new Func<T>(() => Result);
  23:         else
  24:             Constructors.Add(Key, new Func<T>(() => Result));
  25:     }
  26:  
  27:     /// <summary>
  28:     /// Registers an item
  29:     /// </summary>
  30:     /// <param name="Key">Item to register</param>
  31:     /// <param name="Constructor">The function to call when creating the item</param>
  32:     public void Register(Key Key, Func<T> Constructor)
  33:     {
  34:         if (Constructors.ContainsKey(Key))
  35:             Constructors[Key] = Constructor;
  36:         else
  37:             Constructors.Add(Key, Constructor);
  38:     }
  39:  
  40:     /// <summary>
  41:     /// Creates an instance associated with the key
  42:     /// </summary>
  43:     /// <param name="Key">Registered item</param>
  44:     /// <returns>The type returned by the initializer</returns>
  45:     public T Create(Key Key)
  46:     {
  47:         if (Constructors.ContainsKey(Key))
  48:             return Constructors[Key]();
  49:         return default(T);
  50:     }
  51:  
  52:     #endregion
  53: }

Before we talk about the methods, you should note that the class requires two types to be defined. The first is the key that the constructor will be associated with (when you call Create, you'll need to pass this in). The second item is the actual type that you expect from the function that is called. So once you create a Factory object, you can call basically just two methods. The first is the Register method. Calling that allows you to, well, register a constructor with a key. For instance:

   1: TempFactory.Register("Temp1", new Func<ITemp>(() => new Temp1()));

This would register the string "Temp1" with the Temp1 constructor. This of course assumes that the key is a string and the type you're expecting is an ITemp and that Temp1 inherits from ITemp... But assuming all of that, it's fairly simple to grasp. Although if you're curious what a Func is, it's a delegate for a method that has no input but returns an object of a specified type.  Anyway, the second method is the Create method. It takes in a key and spits out an object (assuming the key exists, otherwise it spits out the default value). That's pretty much it. With this, you have yourself a light weight, generic class to handle your factory pattern needs. So try it out, leave feedback, and happy coding.



Comments

decoder
May 28, 2011 4:01 AM
Dude, you gotta a get out the house more. Great work, but you did this for kicks?