付款模块的适当设计模式C# [英] Appropriate design pattern for the payment modules c#

查看:155
本文介绍了付款模块的适当设计模式C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我正在学习设计模式概念,并且还想使用适当的设计模式在我的项目中实现支付模块。为此,我创建了一些示例代码。

As i am learning through design pattern concept and also wanted to implement the payment modules in my project using the proper design pattern. So for that I have created some sample code.

目前,对于付款 PayPal 信用卡。但是具体的实现将在项目上进一步添加。

Currently I have two concrete implementation for the payment PayPal and Credit Card. But the concrete implementation will be added further on the project.

付款服务

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

信用卡和Pay Pal服务

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
    }
}

客户端代码实现

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

获取付款选项

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 thought of implementing this modules using strategy design pattern, and I got deviated from Strategy and ended up doing this way.

这是创建付款模块的正确方法。有没有更好的方法来解决这种情况。这是设计模式吗?

Is this a proper way for creating the payment modules. Is there a more better approach of solving this scenario. Is this a design pattern?

已编辑:

客户代码:

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();

}

策略:

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);
    }
}

此更新是否符合策略模式?

Does this update inlines with the Strategy Pattern?

推荐答案

为此使用抽象工厂的一个主要缺点是它包含一个switch case语句。从本质上讲,这意味着如果您想添加支付服务,则必须更新工厂类中的代码。这违反了开放式委托人,其中规定应开放实体以进行扩展

One major drawback of using an abstract factory for this is the fact that it contains a switch case statement. That inherently means if you want to add a payment service, you have to update the code in the factory class. This is a violation of the Open-Closed Principal which states that entities should be open for extension but closed for modification.

请注意,出于相同的原因,使用 Enum 在付款提供商之间进行切换也是有问题的。这意味着每次添加或删除支付服务时,服务列表都必须更改。更糟糕的是,可以从策略中删除支付服务,但即使该服务无效,它仍然是 Enum 符号。

Note that using an Enum to switch between payment providers is also problematic for the same reason. This means that the list of services would have to change every time a payment service is added or removed. Even worse, a payment service can be removed from the strategy, but still be an Enum symbol for it even though it isn't valid.

另一方面,使用策略模式不需要switch case语句。因此,当您添加或删除付款服务时,现有类没有任何更改。这以及付款选项的数量可能会限制在较小的两位数这一事实,使该策略模式更适合这种情况。

On the other hand, using a strategy pattern doesn't require a switch case statement. As a result, there are no changes to existing classes when you add or remove a payment service. This, and the fact that the number of payment options will likely be capped at a small double-digit number makes the strategy pattern a better fit for this scenario.

// 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;
}



模型



Models

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 实现中转换为具体模型类型的丑陋细节。

Payment Service Abstraction

Here is an abstract class that is used to hide the ugly details of casting to the concrete model type from the IPaymentService implementations.

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);
}



付款服务实施



Payment Service Implementations

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 实现,因此在此不直接引用它们。

Payment Strategy

Here is the class that ties it all together. Its main purpose is to provide the selection functionality of the payment service based on the type of model passed. But unlike other examples here, it loosely couples the IPaymentService implementations so they are not directly referenced here. This means without changing the design, payment providers can be added or removed.

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;
    }
}



用法



Usage

// 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);

其他参考文献:

  • Dependency Injection Unity - Conditional Resolving
  • Factory method with DI and IoC

这篇关于付款模块的适当设计模式C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆