Зависимости внутри внутреннего шестиугольника портов и адаптеров

В это статья Марк Семанн объясняет, как Onion /Hexagonal Architecture (или Ports and Adapters) несколько похожи на многоуровневую архитектуру, когда применяется принцип инверсии зависимостей (DIP). Особенно если вы рассмотрите претензии, сделанные в этом статью , чтобы держать воду, я думаю, что все это довольно ясно и прямолинейно.

Во всяком случае, есть одна цитата о Ports and Adapters , которая заставляла меня задуматься о том, как я структурировал свои классы в прошлом

  

Компоненты во внутреннем шестиугольнике имеют мало или совсем не зависят друг от друга, а компоненты во внешнем шестиугольнике действуют как адаптеры между внутренними компонентами и границами приложения: его порты.

Учитывая, что я хотел бы реализовать некоторую бизнес-логику приложения, называемую App в дальнейшем (это не слишком значимое имя, так или иначе), что позволит отобразить список фильтрованных сотрудников. Отображение списка сотрудников будет предоставлено портом

public interface IEmployeeListProvider
{
    EmployeeList GetEmployees();
}

и сохранение будет другим портом

public interface IEmployeeRpository
{
    IEnumerable<Employee> GetAllEmployees();
    void AddEmployee(Employee employeeToAdd);
    void UpdateEmployee(Employee employeeToUpdate);
    // further method signatures
}

Теперь я бы выполнил свою бизнес-логику

class App : IEmployeeListProvider
{
    // most likely the filters or filter conditions would be injected.
    // and the IEmployeeRepository anyway

    public EmployeeList GetEmployees()
    {
        var employees = employeeRepository.GetAllEmployees();
        var filteredEmployees = FilterEmployees(employees);
        return EmployeeList.FromEnumerable(filteredEmployees);
    }

    private IEnumerable<Employee> FilterEmployees(IEnumerable<IEmployee> employees)
    {
        // elided
    }
}

В основном это то, как я понял Порты и адаптеры как , предложенные Алистером Кокберном . Во всяком случае, эта реализация каким-то образом противоречит цитате Марка Seeman (см. Выше), поскольку App зависит от бота на IEmployeeRepository и порты IEmployeeListProvider. Конечно, можно было бы реструктурировать дизайн, чтобы использовать порт фильтра

public interface IEmployeeFilter
{
    IEnumerable<Employee> FilterEmployees(IEnumerable<Employee> employees);
}

и сделать что-то подобное из пользовательского интерфейса

IEmployeeFilter filter = ...; // however this is constructed
IEmployeeRepository repository = ...; 

// ...

var employees = filter.FilterEmployees(repository.GetAllEmployees());

, но мне это кажется неправильным по нескольким причинам:

  • Пользовательский интерфейс будет зависеть от порта DAL
  • Мы потенциально меняем логику на код пользовательского интерфейса
  • Весьма вероятно, что пользовательский интерфейс станет "зависимым хогом"

Получил ли я всю цитату о Марке Симене, что я там есть какая-то другая часть, которую я получил в корне неправильно?

3 голоса | спросил Paul Kertscher 11 Jam1000000amThu, 11 Jan 2018 10:42:10 +030018 2018, 10:42:10

2 ответа


3

Это не противоречит утверждению. По идее, ваш бизнес-объект, приложение, предоставляет «порты» (два интерфейса), чтобы вы могли подключить другие компоненты сверху. Два интерфейса принадлежат классом App. Да, это зависит от этих интерфейсов, но not зависит от компонентов, которые реализуют или используют их, - и это точно так. IEmployeeRepository - это так называемый обязательный интерфейс (для класса App требуется, чтобы другие компоненты реализовали этот интерфейс, чтобы иметь возможность работать с классом App), а IEmployeeListProvider - это предоставленный интерфейс (предоставляется классом App, для использования другими компонентами). Вы должны рассматривать три типа (App, IEmployeeRepository, IEmployeeListProvider) как одну вещь (и вы поместите их в один и тот же пакет). Затем другие компоненты, реализующие или использующие эти интерфейсы, зависят от них (и, соответственно, от всего триплета).

Вот что (первая часть) принципа инверсии зависимостей гласит: «Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций». Здесь ваш высокоуровневый модуль является классом App, а одним из низкоуровневых модулей будет, скажем, репозиторий. Абстракция, на которую они оба зависят, - это интерфейс IEmployeeRepository, но главное, что этот интерфейс принадлежит классу App, not при реализации репозитория. Таким образом, чтобы определить направление зависимости, вы смотрите на направление стрелки между реализацией репозитория и парой App + IEmployeeRepository.

ответил Filip Milovanović 11 Jpm1000000pmThu, 11 Jan 2018 12:11:58 +030018 2018, 12:11:58
0

Я думаю, что ваша точка зрения Ports & Адаптеры в порядке. Это тоже мое.

В своей статье Марк Семанн говорит о двух шестиугольниках. Я не согласен, я думаю, что есть только один шестиугольник (внутренний). Внутренний шестиугольник - приложение, а стороны внутреннего шестиугольника - это порты. Эти порты представляют собой интерфейсы, которые принадлежат внутреннему шестиугольнику, чтобы общаться с внешним миром (вне внутреннего шестиугольника).

Существует два вида портов:

-Drivers: они предлагают функциональность приложения для внешнего мира (использование границы случая)

-Driven: они абстрагируют то, что нужно приложениям из внешнего мира (хранить /извлекать данные из хранилища данных, отправлять уведомления и т. д.).

В вашем случае ваш интерфейс «IEmployeeListProvider» является портом драйвера. Реализация этого порта находится внутри приложения (внутренний шестиугольник). Эта реализация, для выполнения своей задачи, нуждается в доступе к базе данных (внешний мир), поэтому она использует управляемый порт (ваш интерфейс «IEmployeeRpository»).

Существует также два типа адаптеров (вне внутреннего шестиугольника):

-Drivers: они берут запрос клиента, который хочет использовать приложение, и они вызывают интерфейс порта драйвера.

-Driven: они реализуют ведомый порт, чтобы использовать ресурс, необходимый для приложения.

Итак, мое понимание архитектуры P & аналогично вашей, я не думаю, что вы ошибаетесь.

Я не согласен с статьей Семанна. Он считает, что порты являются границами «своего» внешнего шестиугольника, и адаптеры соединяют эти порты с внутренним шестиугольником. Для меня порты являются границами внутреннего шестиугольника, а адаптеры соединяют порты с «вещами» (людьми, сетью, базами данных и т. Д.) Из внешнего мира, которые либо хотят использовать приложение (драйверы), либо используются приложением (управляемым). Следуя еще одному шагу, Алистер Кокберн разделил ведомые «вещи» на два вида: репозитории и получатели.

Смотрите этот разговор под названием «Alistair in the Hexagone»:

https://www.youtube.com/watch?v=th4AgBcrEHA

https://www.youtube.com/watch?v=iALcE8BPs94

https://www.youtube.com/watch?v=DAe0Bmcyt-4

ответил Juan 13 FebruaryEurope/MoscowbTue, 13 Feb 2018 01:00:16 +0300000000amTue, 13 Feb 2018 01:00:16 +030018 2018, 01:00:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132