Відокремлений інтерфейс (шаблон проєктування)

Відокремлений інтерфейс (англ. Separated Interface) — шаблон проєктування, який допомагає зменшити зв'язність між компонентами шляхом відокремлення абстракції та реалізації.

Опис

Один зі способів покращення архітектури системи — це зменшення зв'язності між компонентами. Цього можна добитись розділивши класи по окремим пакетам та контролювати залежності між ними. Також можна дотримуватись правил залежності. Наприклад, класи бізнес-логіки не повинні викликати класи логіки представлення.

Розглянемо приклад поділу по пакетах класів у триярусній архітектурі. Він передбачає, що рівні діляться по функціоналу, а доступ до них відкритий через інтерфейси взаємодії.

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

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

Реалізація

Помістимо в один модуль класи та залежності необхідні їм для роботи у вигляді інтерфейсів.

namespace Application
{
  internal class WeatherAppService
  {
      private ITimeService _timeService;

      public WeatherAppService(ITimeService timeService)
      {
         _timeService = timeService;
      }
    
      public WeatherForecast GetWeatherForecast()
      {
          var currentTime = _timeService.GetCurrentTime();
  
          return new WeatherForecast
          {
              Time = currentTime,
              TemperatureC = new Random().Next(-20, 55),
          };
      }
  }

  public interface ITimeService
  {
      DateTime GetCurrentTime();
  }
}

Тоді реалізуємо інтерфейси в окремому модулі. Який міститиме прив'язку до конкретних технологій.

namespace Infrastructure
{
  public class TimeService : ITimeService
  {
      public DateTime GetCurrentTime()
      {
          return DateTime.Now;
      }
  }
}

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

Див. також

Джерела