Заглушка сервісу (шаблон проєктування)

Заглушка сервісу (англ. Service Stub) — шаблон проєктування, який дозволяє позбутись залежностей від зовнішніх компонентів.

Опис[ред. | ред. код]

Часто система залежить від зовнішніх сервісів. Зовнішні сервіси можуть створювати неочікувані проблеми, їх не можна контролювати та підтримувати. Ненадійність зовнішніх ресурсів викликає проблеми в самій аплікації. При цьому розробка уповільнюється також через неможливість тестувати логіку аплікації.

Рішенням буде робити залежність не на зовнішній сервіс, а на абстракцію. А при потребі (у разі несправності сервісу, чи тестуванні) використовувати заглушку, цього сервісу, яка виконується локально.

Реалізація[ред. | ред. код]

Нехай, наша аплікація містить операції із конвертуванням грошей. Тоді нам необхідний сервіс, який повертатиме курс валют на цю мить. Представимо таку залежність у вигляді абстракцію.

public interface ICurrencyExchange {      Task<Money> Convert(Money originalAmount, Currency destinationCurrency); } 

Тоді реалізуємо інтерфейси використовуючи необхідний сервіс.

public sealed class CurrencyExchangeService : ICurrencyExchange {     private const Uri _exchangeUrl = new Uri("https://api.exchangeratesapi.io/latest?base=USD");     private readonly IHttpClient _httpClient;          public CurrencyExchangeService(IHttpClient httpClient)     {         _httpClient = httpClient;     }      public async Task<Money> Convert(Money originalAmount, Currency destinationCurrency)     {         var response = await _httpClient.GetAsync(_exchangeUrl);         var usdRates = await response.ReadAsAsync<CurrencyMap>();          decimal usdAmount = usdRates[originalAmount.Currency] / originalAmount.Amount;         decimal destinationAmount = usdRates[destinationCurrency] / usdAmount;          return new Money(destinationAmount, destinationCurrency);     } } 

Та щоб уникнути залежності на зовнішній ресурс, напишемо заглушку, яку будемо використовувати при тестах.

public sealed class CurrencyExchangeStub : ICurrencyExchange {     private readonly Dictionary<Currency, decimal> _usdRates = new Dictionary<Currency, decimal>     {         [Currency.Dollar] = 1m,         [Currency.Euro] = 0.89021m,     };      public Task<Money> Convert(Money originalAmount, Currency destinationCurrency)     {         decimal usdAmount = this._usdRates[originalAmount.Currency] / originalAmount.Amount;         decimal destinationAmount = this._usdRates[destinationCurrency] / usdAmount;          var money = new Money(destinationAmount, destinationCurrency)          return Task.FromResult(money);     } } 

Зв'язок з іншими патернами[ред. | ред. код]

  • Макет об'єкта та заглушка сервісу часто плутають. Та варто розуміти, що макет об'єкта використовуються для імітації поведінки однієї чи декількох функцій та залежно від умов ця імітація може відрізнятись в той час, як заглушка сервісу замінює цілий сервіс та його реалізація залишається незмінною.

Див. також[ред. | ред. код]

Джерела[ред. | ред. код]