Corresponding design pattern for C # payment modules

Since I am studying the concept of design patterns, I also wanted to implement payment modules in my project using the correct design pattern. For this, I created a sample code.

I currently have two specific implementations for payment PayPaland Credit Card. But a specific implementation will be added further on the project.

Payment service

public interface IPaymentService
{
    void MakePayment<T>(T type) where T : class;
}

Credit Card and Pay Pal Service

public class CreditCardPayment : IPaymentService
{
    public void MakePayment<T>(T type) where T : class
    {
        var creditCardModel = (CreditCardModel)(object)type;
        //Implementation CreditCardPayment
    }
}

class PayPalPayment : IPaymentService
{
    public void MakePayment<T>(T type) where T : class
    {
        var payPalModel = (PayPalModel)(object)type;
        //Further Implementation will goes here
    }
}

Client Code Implementation

var obj = GetPaymentOption(payType);
obj.MakePayment<PayPalModel>(payPalModel);

Get payment option

private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
        IPaymentService paymentService = null;

        switch (paymentType)
        {
            case PaymentType.PayPalPayment:
                paymentService = new PayPalPayment();
                break;
            case PaymentType.CreditCardPayment:
                paymentService = new CreditCardPayment();
                break;
            default:
                break;
        }
        return paymentService;
}

I was thinking about implementing these modules using the strategy design pattern, and I deviated from Strategy and ended up doing it.

This is the right way to create payment modules. Is there a better approach to solving this scenario. Is this a design template?

Edited by:

Client code:

static void Main(string[] args)
{
    PaymentStrategy paymentStrategy = null;


    paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)1));
    paymentStrategy.Pay<PayPalModel>(new PayPalModel() { UserName = "", Password = "" });

    paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)2));
    paymentStrategy.Pay<CreditCardModel>(
       new CreditCardModel()
    {
        CardHolderName = "Aakash"
    });

    Console.ReadLine();

}

Strategy:

public class PaymentStrategy
{
    private readonly IPaymentService paymentService;
    public PaymentStrategy(IPaymentService paymentService)
    {
        this.paymentService = paymentService;
    }

    public void Pay<T>(T type) where T : class
    {
        paymentService.MakePayment(type);
    }
}

?

+8
4

, . , , . Open-Closed, , , .

, Enum . , , . , , Enum .

, . . , , , , .

// Empty interface just to ensure that we get a compile
// error if we pass a model that does not belong to our
// payment system.
public interface IPaymentModel { }

public interface IPaymentService
{
    void MakePayment<T>(T model) where T : IPaymentModel;
    bool AppliesTo(Type provider);
}

public interface IPaymentStrategy
{
    void MakePayment<T>(T model) where T : IPaymentModel;
}

public class CreditCardModel : IPaymentModel
{
    public string CardHolderName { get; set; }
    public string CardNumber { get; set; }
    public int ExpirtationMonth { get; set; }
    public int ExpirationYear { get; set; }
}

public class PayPalModel : IPaymentModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

, , IPaymentService.

public abstract class PaymentService<TModel> : IPaymentService
    where TModel : IPaymentModel
{
    public virtual bool AppliesTo(Type provider)
    {
        return typeof(TModel).Equals(provider);
    }

    public void MakePayment<T>(T model) where T : IPaymentModel
    {
        MakePayment((TModel)(object)model);
    }

    protected abstract void MakePayment(TModel model);
}

public class CreditCardPayment : PaymentService<CreditCardModel>
{
    protected override void MakePayment(CreditCardModel model)
    {
        //Implementation CreditCardPayment
    }
}

public class PayPalPayment : PaymentService<PayPalModel>
{
    protected override void MakePayment(PayPalModel model)
    {
        //Implementation PayPalPayment
    }
}

, . - . , IPaymentService IPaymentService . , .

public class PaymentStrategy : IPaymentStrategy
{
    private readonly IEnumerable<IPaymentService> paymentServices;

    public PaymentStrategy(IEnumerable<IPaymentService> paymentServices)
    {
        if (paymentServices == null)
            throw new ArgumentNullException(nameof(paymentServices));
        this.paymentServices = paymentServices;
    }

    public void MakePayment<T>(T model) where T : IPaymentModel
    {
        GetPaymentService(model).MakePayment(model);
    }

    private IPaymentService GetPaymentService<T>(T model) where T : IPaymentModel
    {
        var result = paymentServices.FirstOrDefault(p => p.AppliesTo(model.GetType()));
        if (result == null)
        {
            throw new InvalidOperationException(
                $"Payment service for {model.GetType().ToString()} not registered.");
        }
        return result;
    }
}

// I am showing this in code, but you would normally 
// do this with your DI container in your composition 
// root, and the instance would be created by injecting 
// it somewhere.
var paymentStrategy = new PaymentStrategy(
    new IPaymentService[]
    {
        new CreditCardPayment(), // <-- inject any dependencies here
        new PayPalPayment()      // <-- inject any dependencies here
    });


// Then once it is injected, you simply do this...
var cc = new CreditCardModel() { CardHolderName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(cc);

// Or this...
var pp = new PayPalModel() { UserName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(pp);

:

+7

, . , , MakePayment - IPayResult.

public interface IPayModel { }  // Worth investigating into common shared methods and properties for this 
public interface IPaymentService
{
    void MakePayment(IPayModel  payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
    void MakePayment(T payModel);  // Void here?  Is the status of the payment saved on the concrete pay model?  Why not an IPayResult?
}

public class CreditCardModel : IPayModel
{
    public string CardHolderName { get; set; }
}
public class PayPalModel : IPayModel
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class CreditCardPayment : IPaymentService<CreditCardModel>
{
    public void MakePayment(CreditCardModel payModel)
    {
        //Implmentation CreditCardPayment
    }
    void IPaymentService.MakePayment(IPayModel payModel)
    {
        MakePayment(payModel as CreditCardModel);
    }
}
public class PayPalPayment : IPaymentService<PayPalModel>
{
    public void MakePayment(PayPalModel payModel)
    {
        //Implmentation PayPalPayment
    }
    void IPaymentService.MakePayment(IPayModel payModel)
    {
        MakePayment(payModel as PayPalModel);
    }
}

public enum PaymentType
{
    PayPalPayment = 1,
    CreditCardPayment = 2
}

, , :

static class Program
{
    static void Main(object[] args)
    {
        IPaymentService paymentStrategy = null;
        paymentStrategy = GetPaymentOption((PaymentType)1);
        paymentStrategy.MakePayment(new PayPalModel { UserName = "", Password = "" });

        paymentStrategy = GetPaymentOption((PaymentType)2);
        paymentStrategy.MakePayment(new CreditCardModel { CardHolderName = "Aakash" });

        Console.ReadLine();
    }

    private static IPaymentService GetPaymentOption(PaymentType paymentType) 
    {
        switch (paymentType)
        {
            case PaymentType.PayPalPayment:
                return new PayPalPayment();
            case PaymentType.CreditCardPayment:
                return new CreditCardPayment();
            default:
                throw new NotSupportedException($"Payment Type '{paymentType.ToString()}' Not Supported");
        }
    }
}

, / factory IPayModel . IPaymentService IPayModel factory:

public interface IPaymentService
{
    IPayModel CreatePayModel();
    void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
    new T CreatePayModel();
    void MakePayment(T payModel);
}

public class CreditCardPayment : IPaymentService<CreditCardModel>
{
    public CreditCardModel CreatePayModel()
    {
        return new CreditCardModel();
    }
    public void MakePayment(CreditCardModel payModel)
    {
        //Implmentation CreditCardPayment
    }

    IPayModel IPaymentService.CreatePayModel()
    {
        return CreatePayModel();
    }
    void IPaymentService.MakePayment(IPayModel payModel)
    {
        MakePayment(payModel as CreditCardModel);
    }
} 

:

IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);

var payModel = (PayPalModel)paymentStrategy.CreatePayModel();
payModel.UserName = "";
payModel.Password = "";
paymentStrategy.MakePayment(payModel);
+1

-, Strategy. , PaymentStrategy . Paypal Creditcard. , , , . PaymentStrategy context, .

FactoryMethod, AbstractFactory. factory.

, , Strategy. .

public interface PaymentStrategy {
   void doPayment();
}

public class PaypalStrategy implements PaymentStrategy {
   @Override
   void doPayment() {
      // implement this.
   }
}
public class PaymentService {
    private final PaymentStrategy paymentStrategy;

    public PaymentService(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    public void pay() {
      this.paymentStrategy.doPayment();
      // Do some more here.
    }
}

.

new PaymentService(new PaypalStrategy()).pay();
0

Source: https://habr.com/ru/post/1693484/


All Articles