WloHu
WloHu

Reputation: 1527

C#: switch vs method overload in factory class

Given classes:

enum ThingEnum { A,B,C}

interface IThing { }

class A : IThing { }

class B : IThing { }

class C: IThing { }

I have two implementations of IThingFactory in my head. One using switch:

class ThingFactory
{
    public IThing MakeThing(ThingEnum type)
    {
        switch (type)
        {
            case ThingEnum.A:
                return new A();
                break;
            case ThingEnum.B:
                return new B();
                break;
            case ThingEnum.C:
                return new C();
                break;
            default:
                break;
        }
    }
}

Another using abstraction and method overload:

class ThingFactory
{
    public IThing Make(A a)
    {
        return new A();
    }

    public IThing Make(B a)
    {
        return new B();
    }

    public IThing Make(C a)
    {
        return new C();
    }
}

My questions are:

  1. which implementation is faster,
  2. which is more readable/easier to understand,
  3. which will you use and why?

Upvotes: 2

Views: 1019

Answers (3)

Jürgen Steinblock
Jürgen Steinblock

Reputation: 31723

I would really suggest as IoC container for your approach. Anyway, maybe you just have some classes where you want to do ensure something happens to the class after the .ctor, this approach will work and you don't have to use a switch.

class IThingFactory
{
    public IThing MakeThing<T>() where T : IThing, new()
    {
         var thing = new T();
         thing.Init(); // has to be part of the IThing interface.
         return thing;
    }
}

a more generic approach would be this

class IThingFactory
{
    private IDictionary<Type, Func<IThing>> factories = new Dictionary<Type, Func<IThing>>();

    public void Register(Type t, Func<IThing> factory);
    {
         if(!typeof(IThing).IsAssignableFrom(t))
             throw new ArgumentException("This is not a thing");
         this.factories.Add(t, factory);
    }

    public void Register<T>() where T : IThing, new()
    {
        this.Register<T>(() => new T());
    }

    public void Register<T>(Func<IThing> factory) where T : IThing
    {
        this.Register(typeof(T), factory);
    }

    public IThing MakeThing(Type type);
    {
        if (!factories.ContainsKey(type))
             throw new ArgumentException("I don't know this thing");
        return factories[type]();
    }
}

public void Main()
{
     var factory = new IThingFactory();
     factory.Register(typeof(A), () => new A());
     factory.Register<B>();
     factory.Register<C>(() => new C("Test"));
     var instance = factory.MakeThing(typeof(A));
}

Upvotes: 6

Oxoron
Oxoron

Reputation: 674

You can use something like this:

internal static class Factory
{
    internal static Dictionary<ThingEnum, Func<IThing>> ctors = new Dictionary<ThingEnum, Func<IThing>>
    {
        {ThingEnum.A, () => new A() },
        {ThingEnum.B, () => new B() },
        {ThingEnum.C, () => new C() }
    };

    internal static IThing MakeThing(ThingEnum type)
    {
        return ctors[type]();
    }
}

it's more laconic then first variant. Performance will be almost the same.

Upvotes: 1

qxg
qxg

Reputation: 7036

Using reflection is more maintainable.

  1. Never use switch because when you add new class, you have to modify this switch statement as well.

  2. Second approach is not acceptable. Where are a, b, c from? You have to new them without factory method.

Also check some IoC containers.

Upvotes: 2

Related Questions