Объединение асинхронных и неасинхронных реализаций для шаблона абстрактной фабрики
У нас есть приложение ASP.Net MVC для нашего интернет-магазина. Пользователь должен выбрать один из нескольких способов оплаты, чтобы что-то купить. Для этого мы реализовали абстрактный шаблон фабрики:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
Он используется в нашем действии:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
Проблема возникает, когда мы понимаем, что некоторые способы оплаты требуют асинхронных вызовов внутри. Например, для создания объекта платежа на их стороне должен быть асинхронно вызван метод стороннего сервиса онлайн-платежей через 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());;
}
}
Как я понимаю, это создает два разных потока для обработки действий, которые могут вызвать проблемы с производительностью. Есть ли способ избежать таких последствий? Неужели так плохо использовать Task.Run в конкретном случае?
1 ответ
Неужели так плохо использовать Task.Run в конкретном случае?
Да, главным образом потому, что это излишне усложняет вещи.
Вы можете вернуть выполненное задание, результатом которого является заданное значение, используя Task.FromResult
,
Это полностью синхронно:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
Обратите внимание, что async
здесь отсутствует - это возможно, потому что это деталь реализации, а не часть определения IPaymentService
,