Gaston Milano's WebLog

About something...

Sponsors

News

General

Usability

VS Automation

VSIP

Factory pattern with generics

This post supposes that you have some knowledge about generics and what the Factory pattern are. 

The Factory pattern is a powerful creational pattern; it provides a way to instantiate classes dynamically at run time (For more info http://www.dofactory.com/Patterns/Patterns.aspx).

 

Generics opens a lot of new ways in order to implement many of the GOF patterns. But I was looking for an implementation of the factory pattern using generics and I didn't find something that solve my case.

 

If we need to create a factory class that supports only one kind of object obviously the implementation of the factory using generics is easy.

 

      public interface IFactory<T>

      {

            T Create();

      }

 

      public class Factory<T> : IFactory<T> where T : new()

      {

            public T Create()

            {

                  return new T();

            }

      }

 

 

But as Hugo Troche explain in this article

 “Generics change the basic implementation dynamic of factories. With factories the system defines the type of an object at run time. With generics the compiler has to be able to figure out the type of all objects at compile time”

 

The problem is when we need to create (as the pattern say) a different object depending on a key.

 

Let me explain a bit more what I’m going to try to solve. Suppose the common use case for a factory pattern:

 

public interface ICar

      {

            string Name { get; }

      }

 

      public class Ford : ICar

      {

            #region ICar Members

 

            public string Name

            {

                  get { return "Ford"; }

            }

 

 

            #endregion

      }

 

      public class Fiat : ICar

      {    

            #region ICar Members

 

            public string Name

            {

                  get { return "Fiat"; }

            }

 

            #endregion

     

      }

     

 

Hugo in his article found a solution using a combination of the Factory and a Chain of Responsibility patterns. It is a cool solution but you should change your classes definitions in order to implement the Chain of responsibility.

I was looking a solution for this use case with the following characteristics:

 

-         The factory should have a strong typed method that returns a Car. (ie Car Create(string name) )

-         The factory never rise an InvalidCastException

-         It should be implemented using Generics in order to use it for other cases.

 

So I started defining the interface for the factory

 

      public interface IFactory<K, T> where K : IComparable

      {

            T Create();

      }

 

After I defined a helper interface for the items in the factory

 

      public interface IFactoryElement

      {

            object New();

      }

 

An implementation of the IFactoryElement

 

      public class FactoryElement<T> : IFactoryElement

                                          where T : new()

      {

 

            public object New()

            {

                  return new T();

            }

 

      }

 

As you can see the New method returns an object and not T. If it returns T we are defining that the Create method of the factory will return always something of type T.

 

 

Now the factory

 

      public class Factory<K, T> : IFactory<K, T> where K : IComparable

      {

            /// Elements that can be created

            Dictionary<K, IFactoryElement> elements = new Dictionary<K, IFactoryElement>();

 

            /// <summary>

            ///  Add a new creatable kind of object to the factory. Here is the key with the beauty of the constrains in generics. Look that we are saying that V should be derived of T and it must be creatable

            /// </summary>

            public void Add<V>(K key) where V : T, new()

            {

                  elements.Add(key, new FactoryElement<V>());

            }

 

            public T Create(K key)

            {

                  if (elements.ContainsKey(key))

                  {

                        return (T) elements[key].New();

                  }

                  throw new ArgumentException();

            }

      }

 

Note that the Create method never raise an InvalidCastException because elements[key] is going to return something of type V, and T is the base class of V !!

     

 

So for the use case of the cars I can use my generic factory in this way:

 

      public class CarFactory

      {

            Factory<string, ICar> internalFactory = new Factory<string, ICar>();

 

            public class CarFactory()

            {

                  internalFactory.Add<Fiat>("fiat");

                  internalFactory.Add<Ford>("ford");

            }

 

            public ICar Create(string carType)

            {

                  return internalFactory.Create(carType);

            }

      }

 

I could use directly the factory without this class, the only issue is that it has the Add method as public.

Comments in order to improve this implementation are welcome !!

 

 

 

 

 

 

 

Comments

Richard Broida said:

Why make the caller create and pass a FactoryElement to Add()? Instead:

public void Add<V>(K key) where V : T, new()
{
elements.Add(key, , new FactoryElement<V>());
}

This way the FactoryElement class needn't be visible to the caller at all.
# July 29, 2005 8:48 AM

GMilano said:

Hi,

Because 3 am is to late for programming ;) I update the post with your comment.

Thank you !!
# July 29, 2005 8:53 AM

Albina-ux said:

<a href= membres.lycos.fr/maffals >genetic disorters</a>

# December 26, 2008 5:34 AM

Denis said:

Shouldn't this read:

public interface IFactory<K, T> where K : IComparable

     {

           T Create();

     }

TO:

public interface IFactory<K, T> where K : IComparable

     {

           T Create(K key);

     }

# February 17, 2009 10:48 AM

Dumitru Ciorb?? » Blog Archive » Factory Method: realizare tradi??ional?? sau Generics said:

Pingback from  Dumitru Ciorb??  &raquo; Blog Archive   &raquo; Factory Method: realizare tradi??ional?? sau Generics

# June 18, 2009 3:34 PM

Tom said:

Why do you need the factory element or the dictionary?  Will this work:

   public static class Factory<I,T> where T : I, new()

   {

       public static I Create()

       {

           return new T();

       }

   }

I represents an interface that T extends.

# July 31, 2009 11:31 AM

Roman Golubin said:

Great article! Thanks!

# August 19, 2009 10:41 AM

Roman Golubin said:

Hmmm...

We can use the Func <T> that would simplify the factory (only one helper generic class required now):

 #region generic factory

 public class Factory<K, T> where K : IComparable

 {

   Dictionary<K, Func<T>> elements = new Dictionary<K, Func<T>>();

   public void Add<V>(K key) where V : T, new()

   {

     elements.Add(key, ()=>new V());

   }

   public T Create(K key)

   {

     if (elements.ContainsKey(key))

     {

       return elements[key]();

     }

     throw new ArgumentException();

   }

 }

 #endregion

# August 19, 2009 11:32 AM

Roman Golubin said:

And now we can simplify CarFactory too:

 public class CarFactory : Factory<string, ICar>

 {

   public class CarFactory()

   {

     Add<Fiat>("fiat");

     Add<Ford>("ford");

   }

 }

# August 19, 2009 11:45 AM

Jan said:

:c I only have VS2005.. could you simplify this expression

elements.Add(key, ()=>new V());

I would like not a lambda expression but using delegate..

forgive my being novice to this kind of programming..

Thanks,

janverge

# May 15, 2010 10:23 PM

Frank said:

()=>new V()

=

delegate () {return new V();}

# October 14, 2011 7:00 AM

mathias said:

But if you are like me new to all this, then you want to know why the compiler is not happy:

In the final class this:

           public class CarFactory()

           {

                 internalFactory.Add<Fiat>("fiat");

                 internalFactory.Add<Ford>("ford");

           }

should be:

           public CarFactory()

           {

                 internalFactory.Add<Fiat>("fiat");

                 internalFactory.Add<Ford>("ford");

           }

# February 1, 2012 7:47 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)