views:

597

answers:

7

Is it a good idea to have a factory class using generics to instantiate objects?

Let's say I have a class Animal and some subclasses (Cat, Dog, etc):

abstract class Animal
{
    public abstract void MakeSound();
}

class Cat : Animal
{
    public override void MakeSound()
    {
        Console.Write("Mew mew");
    }
}

class Dog : Animal
{
    public override void MakeSound()
    {
        Console.Write("Woof woof");
    }
}

static class AnimalFactory
{
    public static T Create<T>() where T : Animal, new()
    {
        return new T();
    }
}

Then in my code I would use AnimalFactory like this:

class Program
{
    static void Main(string[] args)
    {
        Dog d = AnimalFactory.Create<Dog>();
        d.MakeSound();
    }
}
+3  A: 

Depends on what you want to do with it. The example you gave is not that helpful, as all it does is simply call new() which is something you can do in your code as well. A factory is more useful if you want to place logic which has to be ran during the object creation process somewhere outside the object to create but also away from the code which instantiates the objects.

In that light, it depends on what logic you want to run in your factory and if that logic is also writable using the same generic constraints as the factory. If not, you'll likely need a pattern called Abstract factory, which uses a general factory to instantiate the right specific factory behind the scenes for the type to create the object at hand.

Frans Bouma
+2  A: 

Yes, factory methods in non-generic classes can often be useful. In particular, generic methods can have type inference applied to them, whereas generic types can't.

I sometimes have two layers of factories, too - for a generic type with 2 type parameters, I might have:

class Foo
{
    static Foo<TKey, TValue> Create<TKey, TValue>(TKey key, TValue value) 
    {...}
}

class Foo<TKey>
{
    static Foo<TKey, TValue> Create<TValue>(TValue value)
    {...}
}

class Foo<TKey, TValue>
{
}

This allows:

Foo.Create(x, y);
Foo<string>.Create(y);
new Foo<string, int>(x, y);

I have a blog entry with more examples and reasoning.

Jon Skeet
A: 

using generics for your constructor is called the abstract factory pattern.

Its good but only if you're using it, in this example you've got some of the defaults in the factory at least.

static class AnimalFactory
{
    public static Animal Create<T>() where T : Animal
    {
       return Create<T>("blue");
    }

    public static Animal Create<T>(string colour) where T : Animal, new()
    {
       return new T() {Colour = colour};
    }
}
Scott Cowan
+1  A: 

One of the more annoying things that come from this, and there might be a way around this, is that you are stuck with using a parameterless constructor. Far as I know, you can't do this:

public class Factory  
{
  public static T Create<T>() where T : ParentClass, new(String)
  {

  }
}

Or this

public class Factory  
{
  public static T Create<T>() where T : ParentClass
  {
    T child = new T("hi")
  }
}

Or even more fun like:

public class Factory  
{
  public static T Create<T>() where T : ParentClass, new()
  {
    T child;

    child = new T();

    if (child is ChildClass)
    {
      child = new ChildClass("hi");
    }

    return child;
  }
}

Which can limit you to certain class design. This may be a problem if you don't want just the default constructor called.

That is unless someone has found a way to get around this.

I know I've run into this problem with Activator.CreateInstance() also since in reality all that does is call the parameterless constructor.

Programmin Tool
A: 

Is it a good idea to have a factory class using generics to instantiate objects?

For the case you described, no it isn't. You'd just be using a pattern for the sake of using a pattern and from the example, is only going to unnecessarily compicate things.

Now if your app has several objects implementing some interface and you load one of those objects based on a config file, then yes, it makes sense to use a factory to create that object.

The generics portion of this problem would actually come in the factory implementation itself. I have no supporting code, but this is how I would envision the calling code to look:

Factory<IAwesome> awesomeFactory = new Factory<IAwesome>();
IAwesome awesomeObject = awesomeFactory.Load(configValue);
Austin Salonen
A: 

I would recommend separating the factory concern from the constructor concern. This allows varying instantiation strategies:

public interface IFactory<T>
{
    T Create();
}

public class DefaultConstructorFactory<T> : IFactory<T> where T : new()
{
    public T Create()
    {
        return new T();
    }
}

public class ActivatorFactory<T> : IFactory<T>
{
    public T Create()
    {
        return Activator.CreateInstance<T>();
    }
}

public class AnimalTamer<TAnimal> where TAnimal : Animal
{
    IFactory<TAnimal> _animalFactory;

    public AnimalTamer(IFactory<TAnimal> animalFactory)
    {
        if(animalFactory == null)
        {
            throw new ArgumentNullException("animalFactory");
        }

        _animalFactory= animalFactory;
    }

    public void PutOnShow()
    {
        var animal = _animalFactory.Create();

        animal.MakeSound();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var tamer = new AnimalTamer<Tiger>(new DefaultConstructorFactory<Tiger>());

        tamer.PutOnShow();
    }
}
Bryan Watts
A: 

yes. the creational design patterns (http://en.wikipedia.org) work well with generics. and generics can be a bit complicated (http://www.artima.com/intv/genericsP.html), so it's fine to hide any construction complexity in some kind of factory to make it easier for the client.

Ray Tayek