Factory Method – Handling Objects with Multiple Complex Constructors

cdesign-patternsfactory-methodlegacy code

I'm refactoring a legacy codebase.
I have 4 very similar objects that I decided would be a good target for becoming polymorphic, so I moved all the common code to a base class and added an interface.

The real problem arises when trying to create those objects. Every class has 3 different constructors with 5-10 parameters each, used in different cases based on the context.
I already know those classes have too much going on, and would actually be better split in different, smaller classes, each one dealing with one case, however this is a legacy codebase and I can't do so many changes to the existing code.

At the moment my code is something like this:

public class HandlerFactory
{
    public static IHandler CreateInstance(HandlerType param1, string param2, ..., string param8)
    {
        switch(param1)
        {
            case HandlerType.Type1
                return new Handler1(param2, ..., param8)
            case HandlerType.Type2
                return new Handler2(param2, ..., param8)
            case HandlerType.Type3
                return new Handler3(param2, ..., param8)
            case HandlerType.Type4
                return new Handler4(param2, ..., param8)
        }
    }

    public static IHandler CreateInstance(HandlerType param1, int param2, ..., DateTime param10)
    {
        switch(param1)
        {
            case HandlerType.Type1
                return new Handler1(param2, ..., param10)
            case HandlerType.Type2
                return new Handler2(param2, ..., param10)
            case HandlerType.Type3
                return new Handler3(param2, ..., param10)
            case HandlerType.Type4
                return new Handler4(param2, ..., param10)
        }
    }

    public static IHandler CreateInstance(HandlerType param1, string param2, ..., CustomClass param5)
    {
        switch(param1)
        {
            case HandlerType.Type1
                return new Handler1(param2, ..., param5)
            case HandlerType.Type2
                return new Handler2(param2, ..., param5)
            case HandlerType.Type3
                return new Handler3(param2, ..., param5)
            case HandlerType.Type4
                return new Handler4(param2, ..., param5)
        }
    }
}

However, I hate having 3 factory methods, as I now have to edit three of them if I were to add another Handler (the main reason I'm doing this refactoring).

Is there a way I can keep just one factory method with a single switch?

Best Answer

The answer provided by @JohnWu is very elegant and I like it a lot. Allow me to provide an alternative.

You could use Abstract Factory Pattern. You would basically have one big factory of factories, which would then produce the concrete factories for concrete handlers. Then, should you need another handler, all you would need to do is write one factory for that particular handler. It would be something along these lines:

public interface IHandler
{
}

public class Handler1 : IHandler
{
    public Handler1(string param1, string param2)
    {
    }

    public Handler1(int param1, int param2)
    {
    }
}

public class Handler2 : IHandler
{
    public Handler2(string param1, string param2)
    {
    }

    public Handler2(int param1, int param2)
    {
    }
}

For simplicity, I have only two Handler classes with two different constructors. I believe the solution still can be applied to your case. Next, we have factories:

   public interface IHandlerFactory
    {
        IHandler Create(string param1, string param2);
        IHandler Create(int param1, int param2);
    }

    public class Handler1Factory : IHandlerFactory
    {
        public IHandler Create(int param1, int param2)
        {
            return new Handler1(param1, param2);
        }

        public IHandler Create(string param1, string param2)
        {
            return new Handler1(param1, param2);
        }
    }

    public class Handler2Factory : IHandlerFactory
    {
        public IHandler Create(int param1, int param2)
        {
            return new Handler2(param1, param2);
        }

        public IHandler Create(string param1, string param2)
        {
            return new Handler2(param1, param2);
        }
    }

    public class HandlerFactory
    {
        public static IHandler Create(IHandlerFactory factory, string param1, string param2)
        {
            return factory.Create(param1, param2);
        }

        public static IHandler Create(IHandlerFactory factory, int param1, int param2)
        {
            return factory.Create(param1, param2);
        }
    }

The alternative here would be to have a HandlerFactory class that would have a property of IHandlerFactory type, and the methods would not be static and would not have IHandlerFactory parameter in them. Obviously, an object of HandlerFactory class would need to be instantiated at some point.

The usage would go somehow like this:

public class Example
{
    public void ExampleMethod()
    {
        Handler1Factory factory1 = new Handler1Factory();
        var handler1 = HandlerFactory.Create(factory1, "parameter1", "parameter2");

        Handler2Factory factory2 = new Handler2Factory();
        var handler2 = HandlerFactory.Create(factory2, 1, 2);
    }
}

The solution clearly divides the code by purpose, and most importantly, should you have the need for another handler, you would not need to change the existing code. All you would have to do is write a factory for that particular handler.

Remember, this is only possible because all handlers have the constructors with same parameter lists. The design would be somewhat different if that was not the case.