简体   繁体   中英

How to use Reflection in factory design patterns in C# .Net core

I've implementing the Factory Method in c#.Net core in the following way.I have several concrete products let's say Gateway1 and Gateway2

public interface IGateway
{
    void Test();
}

ConcreteCreator:

public class PaymentFactory
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;
    private readonly IPaymentGatewayRepository _paymentGatewayRepository;

    public PaymentFactory(IPaymentTransactionRepository paymentTransactionRepository,
        IPaymentGatewayRepository paymentGatewayRepository)
    {
        _paymentTransactionRepository = paymentTransactionRepository;
        _paymentGatewayRepository = paymentGatewayRepository;
    }

    public IGateway ExecuteCreation(string bank)
    {
        switch (bank)
        {
            case "Gateway1":
                {
                    return new Gateway1(_paymentGatewayRepository);
                }
            case "Gateway2":
                {
                    return new Gateway2(_paymentTransactionRepository, _paymentGatewayRepository);

                }
            default:
                {
                    return null;

                }
        }
    }

}

ConcreteProducts:

public class Gateway1 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;

    public Gateway1(IPaymentTransactionRepository paymentGatewayRepository)
    {
        _paymentGatewayRepository = paymentGatewayRepository;
    }

    public void Test()
    {
        //code
    }
}

public class Gateway2 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;
    private readonly IPaymentGatewayRepository _paymentGatewayRepository;

    public Gateway2(IPaymentTransactionRepository paymentGatewayRepository,
        IPaymentGatewayRepository paymentGatewayRepository)
    {
        _paymentGatewayRepository = paymentGatewayRepository;
        _paymentGatewayRepository = paymentGatewayRepository;
    }

    public void Test()
    {
        //code
    }
}

This code is running but I want to make two changes to it.

1- How to implementing the Factory Method by Reflection?

2- How to pass in multiple parameters to Create ConcreteProducts ?

Thanks in advance.

you can use bellow code.You need to change the PaymentFactory as follows. you can user IServiceProvider Injection of the service into the constructor of the class where it's used.

ConcreteProducts Names:

public enum PaymentGatewayEnum
{
    Gateway1 = 1,
    Gateway2 = 2,
}

then PaymentFactory:

public class PaymentFactory
{
    private readonly IServiceProvider _serviceProvider;
    public PaymentFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IGateway ExecuteCreation(PaymentGatewayEnum bank)
    {
        var services = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
            .Where(x => typeof(IGateway).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
            .FirstOrDefault(x => string.Equals(x.Name, bank.ToString(), StringComparison.CurrentCultureIgnoreCase));

        return Activator.CreateInstance(services, _serviceProvider) as IGateway;
    }

}

and then:

public class Gateway1 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;

    public Gateway1(IServiceProvider serviceProvider)
    {
        _paymentTransactionRepository = (IPaymentTransactionRepository)serviceProvider.GetService(typeof(IPaymentTransactionRepository));
    }

    public void Test()
    {
        //code
    }
}

public class Gateway2 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;
    private readonly IPaymentGatewayRepository _paymentGatewayRepository;

    public Gateway2(IServiceProvider serviceProvider)
    {
        _paymentTransactionRepository = (IPaymentTransactionRepository)serviceProvider.GetService(typeof(IPaymentTransactionRepository));
        _paymentGatewayRepository = (IPaymentGatewayRepository)serviceProvider.GetService(typeof(IPaymentGatewayRepository));
    }

    public void Test()
    {
        //code
    }
}

An alternative to Reza Jenabi's solution is the following:

Enum to select between gateways:

public enum PaymentGatewayType
{
    GATEWAY1,
    GATEWAY2,
}

The factory interface:

public interface IPaymentFactory
{
}

The factory, which can be registered as a singleton:

public class PaymentFactory : IPaymentFactory
{
    private Dictionary<PaymentGatewayType, Func<IGateway>> GatewayTypes 
       = new Dictionary<PaymentGatewayType, Func<IGateway>>();

    public PaymentFactory(IServiceProvider serviceProvider)
    {
        Gateways = Assembly.GetExecutingAssembly().GetTypes()
            .Where(t => typeof(IGateway).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract)
            .Select(t => new Func<IGateway>(() => 
                 ActivatorUtilities.CreateInstance(serviceProvider, t) as IGateway))
            .ToDictionary(f => f().GatewayType);
    }

    public IGateway GetGateway(PaymentGatewayType gatewayType)
    {
        return GatewayTypes[gatewayType]();
    }
}

The gateways:

public interface IGateway
{
    //The GatewayType property is important as that's what the PaymentFactory uses
    // as a discriminator (see .ToDictionary(f => f().GatewayType);)
    PaymentGatewayType GatewayType{ get; }
    void Test();
}

public class Gateway1 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;

    //Here we override the GatewayType property in the interface to set which 
    //gateway this class belongs to
    public override PaymentGatewayType GatewayType => PaymentGatewayType.GATEWAY1;

    public Gateway1(IPaymentTransactionRepository paymentGatewayRepository)
    {
        _paymentGatewayRepository = paymentGatewayRepository;
    }

    public void Test()
    {
        //code
    }
}

public class Gateway2 : IGateway
{
    private readonly IPaymentTransactionRepository _paymentTransactionRepository;
    private readonly IPaymentGatewayRepository _paymentGatewayRepository;

    //Here we override the GatewayType property in the interface to set which 
    //gateway this class belongs to
    public override PaymentGatewayType GatewayType => PaymentGatewayType.GATEWAY2;

    public Gateway2(IPaymentTransactionRepository paymentGatewayRepository,
        IPaymentGatewayRepository paymentGatewayRepository)
    {
        _paymentGatewayRepository = paymentGatewayRepository;
        _paymentGatewayRepository = paymentGatewayRepository;
    }

    public void Test()
    {
        //code
    }
}

Then in the calling code something like the following:

public class GatewayService
{
    private readonly IPaymentFactory _paymentFactory;

    public GatewayService(IPaymentFactory paymentFactory)
    {
        _paymentFactory = paymentFactory;
    }

    public void DoSomething(PaymentGatewayType gatewayType)
    {
        IGateway gateway = _paymentFactory.GetGateway(gatewayType);

        gateway.Test();
    }
}

To add more Gateways simply add a new enum Value, eg GATEWAY3 and create a new Gateway3 class that inherits from IGateway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM