结合抽象工厂模式的异步和非异步实现
Combine async and not async implementations for the abstract factory pattern
我们的在线商店有一个 ASP.Net MVC 应用程序。用户必须从多种付款方式中进行选择才能购买商品。为此,我们实现了一个抽象工厂模式:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
在我们的Action中使用:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
当我们了解某些支付方式需要内部异步调用时,就会出现问题。例如第 3 方在线支付服务方法必须通过 http 异步调用以在其端创建支付对象。实现:
public class OnlinePaymentService : IPaymentService
{
private readonly IOnlinePaymentServiceApiClient _client;
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
var result = await _client.CreatePaymentAsync();
return result;
}
}
所以我们提出了一个问题:如何处理不同支付方式的异步和同步场景。我们决定让一切都异步。更新代码:
public interface IPaymentService
{
Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
到目前为止一切顺利,但为了对所有其他支付方式实施此操作,我们不得不使用 Task.Run:
public class CashPaymentService : IPaymentService
{
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
return await Task.Run(() => new PaymentSettingsModel());;
}
}
据我所知,这会创建两个不同的线程来处理 Action,这可能会导致 performance issue。
有没有办法避免这样的后果?在特定情况下使用 Task.Run 真的很糟糕吗?
Is it really so bad to use Task.Run in particular case?
是的,主要是因为它不必要地使事情复杂化。
您可以 return 一个已完成的任务,其结果是使用 Task.FromResult
的给定值。
这是完全同步的:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
请注意,此处缺少 async
- 这是可能的,因为它是一个实现细节,而不是 IPaymentService
.
定义的一部分
我们的在线商店有一个 ASP.Net MVC 应用程序。用户必须从多种付款方式中进行选择才能购买商品。为此,我们实现了一个抽象工厂模式:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
在我们的Action中使用:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
当我们了解某些支付方式需要内部异步调用时,就会出现问题。例如第 3 方在线支付服务方法必须通过 http 异步调用以在其端创建支付对象。实现:
public class OnlinePaymentService : IPaymentService
{
private readonly IOnlinePaymentServiceApiClient _client;
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
var result = await _client.CreatePaymentAsync();
return result;
}
}
所以我们提出了一个问题:如何处理不同支付方式的异步和同步场景。我们决定让一切都异步。更新代码:
public interface IPaymentService
{
Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
到目前为止一切顺利,但为了对所有其他支付方式实施此操作,我们不得不使用 Task.Run:
public class CashPaymentService : IPaymentService
{
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
return await Task.Run(() => new PaymentSettingsModel());;
}
}
据我所知,这会创建两个不同的线程来处理 Action,这可能会导致 performance issue。 有没有办法避免这样的后果?在特定情况下使用 Task.Run 真的很糟糕吗?
Is it really so bad to use Task.Run in particular case?
是的,主要是因为它不必要地使事情复杂化。
您可以 return 一个已完成的任务,其结果是使用 Task.FromResult
的给定值。
这是完全同步的:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
请注意,此处缺少 async
- 这是可能的,因为它是一个实现细节,而不是 IPaymentService
.