付款模块的适当设计模式C# [英] Appropriate design pattern for the payment modules 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屋!