9
\$\begingroup\$

I am learning design patterns and this is my sample code where I have implemented Factory pattern and instance creation I have delegated to Unity container Framework(DI) to build the loosely coupled system.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;

namespace DesignPatternsDemo
{
    class Program
    {
        static void Main(string[] args)
        {

            iPaymentGateway gateway = PaymentGatwayFactory.NewPaymentGatway(GateWay.SHIFT4);
            gateway.CreatePaymentGateway();
            gateway = PaymentGatwayFactory.NewPaymentGatway(GateWay.WELLSFARGO);
            gateway.CreatePaymentGateway();
            gateway = PaymentGatwayFactory.NewPaymentGatway(GateWay.PROTOBASE);
            gateway.CreatePaymentGateway();
            Console.ReadLine();
        }

        enum GateWay
        {
            PROTOBASE = 1,
            SHIFT4 = 2,
            WELLSFARGO = 3
        }

         //Factory class
        class PaymentGatwayFactory
        {
            public static iPaymentGateway NewPaymentGatway(GateWay GateWayType)
            {
                 //Dependency injection using unity container
                var container = new UnityContainer();
                iPaymentGateway result = null;
                switch (GateWayType)
                {
                    case GateWay.SHIFT4:
                        container.RegisterType<iPaymentGateway, SHIFT4Gateway>();
                        result = container.Resolve<SHIFT4Gateway>();
                        break;
                    case GateWay.WELLSFARGO:
                        container.RegisterType<iPaymentGateway, WellsFargoGateway>();
                        result = container.Resolve<WellsFargoGateway>();
                        break;
                    default:
                        container.RegisterType<iPaymentGateway, ProtobaseGateway>();
                        result = container.Resolve<ProtobaseGateway>();
                        break;
                }

                return result;
            }
        }

        class WellsFargoGateway : iPaymentGateway
        {
            public void CreatePaymentGateway()
            {
                Console.WriteLine("Implement Wells Fargo logic");
            }
        }

        class SHIFT4Gateway : iPaymentGateway
        {
            public void CreatePaymentGateway()
            {
                Console.WriteLine("Implement SHIFT4 logic");
            }
        }

        class ProtobaseGateway : iPaymentGateway
        {
            public void CreatePaymentGateway()
            {
                Console.WriteLine("Implement Protobase logic");
            }
        }

        interface iPaymentGateway
        {
            void CreatePaymentGateway();
        }
    }
}

Is this is the right way of implementing Factory pattern and using the Unity framework?

\$\endgroup\$

1 Answer 1

10
\$\begingroup\$

The following code should tell a story as it is reviewed. There are not many comments as the code has been simplified to be easy to understand as it speaks for itself. I suggest comparing it to what you had before and observe the difference in strategy taken to achieve the factory pattern with DI.

Apart from the composition root, note the separation of concerns and loose coupling of all members involved. The factory in the original post was tightly coupled to the UnityContainer and was also creating an instance every time the factory method was called. The container should only be created once in the composition root of the application.

public interface IPaymentGateway {
    void Invoke();
}

public class WellsFargoGateway : IPaymentGateway {
    public void Invoke() {
        Console.WriteLine("Implement Wells Fargo logic");
    }
}

public class SHIFT4Gateway : IPaymentGateway {
    public void Invoke() {
        Console.WriteLine("Implement SHIFT4 logic");
    }
}

public class ProtobaseGateway : IPaymentGateway {
    public void Invoke() {
        Console.WriteLine("Implement Protobase logic");
    }
}

internal class NullGateway : IPaymentGateway {

    static Lazy<IPaymentGateway> nullObject = new Lazy<IPaymentGateway>(() => new NullGateway());

    public static IPaymentGateway Empty {
        get { return nullObject.Value; }
    }

    private NullGateway() {

    }

    public void Invoke() {
        //No-op
    }
}


public enum GateWay {
    PROTOBASE = 1,
    SHIFT4 = 2,
    WELLSFARGO = 3
}

public interface IPaymentGatewayFactory {
    IPaymentGateway Create(GateWay GateWayType);
}

public class DefaultPaymentGatewayFactory : IPaymentGatewayFactory {

    readonly Func<GateWay, IPaymentGateway> factoryFactory;

    public DefaultPaymentGatewayFactory(Func<GateWay, IPaymentGateway> factoryFactory) {
        this.factoryFactory = factoryFactory;
    }

    public IPaymentGateway Create(GateWay GateWayType) {
        return factoryFactory(GateWayType);
    }
}

public static class CompositionRoot {
    public static IUnitContainer Configure() {
        //Dependency injection using unity container
        var container = new UnityContainer();
        //Register the gateways using named mappings
        container.RegisterType<IPaymentGateway, WellsFargoGateway>(GateWay.WELLSFARGO.ToString());
        container.RegisterType<IPaymentGateway, SHIFT4Gateway>(GateWay.SHIFT4.ToString());
        container.RegisterType<IPaymentGateway, ProtobaseGateway>(GateWay.PROTOBASE.ToString());
        //create the strategy
        Func<GateWay, IPaymentGateway> factoryFactory = (gatewayType) =>
            container.Resolve<IPaymentGateway>(gatewayType.ToString()) ?? NullGateway.Empty;
        //register factory
        var factory = new DefaultPaymentGatewayFactory(factoryFactory);
        container.RegisterInstance<IPaymentGatewayFactory>(factory);

        return container;
    }

}

class Program {
    static void Main(string[] args) {            
        var container = CompositionRoot.Configure();
        var factory = container.Resolve<IPaymentGatewayFactory>();
        IPaymentGateway gateway = factory.Create(GateWay.SHIFT4);
        gateway.Invoke();
        gateway = factory.Create(GateWay.WELLSFARGO);
        gateway.Invoke();
        gateway = factory.Create(GateWay.PROTOBASE);
        gateway.Invoke();
        Console.ReadLine();
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ I like your approach, one could as well put the logic for the strategy directly into a specific "unity payment gateway factory" implementing IPaymentGatewayFactory and pass the container via DI into it. This would simplify the creation of unit tests for it. \$\endgroup\$
    – royalTS
    Sep 1, 2021 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.