Что такое антикоррупционный слой и как он используется?


151

Я пытаюсь понять, что на самом деле означает антикоррупционный слой. Я знаю, что это способ перехода / работы с устаревшим кодом или плохими API. Я не понимаю, как это работает и что делает его чистым отделением от нежелательного слоя.

Я провел некоторый поиск, но не могу найти простых примеров или объяснений, поэтому я ищу человека, который понимает это и может объяснить это простыми примерами. Ответ, который удовлетворит мой вопрос, должен быть простым (не обязательно коротким) и содержать понятные примеры реализации и использования.

Смотрите этот вопрос , для моего варианта использования.

Ответы:


147

Представьте, что вы должны использовать чужой код, который разработан, как показано ниже:

    class Messy {
        String concat(String param, String str) { /* ... */ }
        boolean contains(String param, String s) { /* ... */ }
        boolean isEmpty(String param) { /* ... */ }
        boolean matches(String param, String regex) { /* ... */ }
        boolean startsWith(String param, String prefix) { /* ... */ }
    }

Теперь представьте, что вы обнаружите, что ваш код, который зависит от него, выглядит следующим образом:

String process(String param) {
    Messy messy = new Messy();
    if (messy.contains(param, "whatever")) {
        return messy.concat(param, "-contains");
    }
    if (messy.isEmpty(param)) {
        return messy.concat(param, "-empty");
    }
    if (messy.matches(param, "[whatever]")) {
        return messy.concat(param, "-matches");
    }
    if (messy.startsWith(param, "whatever")) {
        return messy.concat(param, "-startsWith");
    }
    return messy.concat(param, "-whatever");
    // WTF do I really need to repeat bloody "param" 9 times above?
}

... и что вы хотите упростить использование, в частности, избавиться от повторного использования параметров, которые просто не нужны для вашего приложения.

Итак, вы начинаете создавать антикоррупционный слой.

  1. Прежде всего, убедитесь, что ваш «основной код» не ссылается Messyнапрямую. Например, вы организуете управление зависимостями таким образом, что попытка доступа Messyне скомпилируется.

  2. Во-вторых, вы создаете выделенный модуль «layer», который является единственным доступным, Messyи представляете его своему «основному коду» таким образом, чтобы он был более понятным для вас.

Код слоя будет выглядеть следующим образом:

    class Reasonable { // anti-corruption layer
        String param;
        Messy messy = new Messy();
        Reasonable(String param) {
            this.param = param;
        }
        String concat(String str) { return messy.concat(param, str); }
        boolean contains(String s) { return messy.contains(param, s); }
        boolean isEmpty() { return messy.isEmpty(param); }
        boolean matches(String regex) { return messy.matches(param, regex); }
        boolean startsWith(String prefix) { return messy.startsWith(param, prefix); }
    }

В результате ваш «основной код» не связывается Messy, используя Reasonableвместо этого примерно следующее:

String process(String param) {
    Reasonable reasonable = new Reasonable(param);
    // single use of "param" above and voila, you're free
    if (reasonable.contains("whatever")) {
        return reasonable.concat("-contains");
    }
    if (reasonable.isEmpty()) {
        return reasonable.concat("-empty");
    }
    if (reasonable.matches("[whatever]")) {
        return reasonable.concat("-matches");
    }
    if (reasonable.startsWith("whatever")) {
        return reasonable.concat("-startsWith");
    }
    return reasonable.concat("-whatever");
}

Заметьте, что все еще есть небольшая путаница, Messyно теперь она достаточно глубоко спрятана Reasonable, что делает ваш «основной код» достаточно чистым и свободным от повреждений, которые могут возникнуть при непосредственном использовании Messyвещей.


Приведенный выше пример основан на том, как антикоррупционный слой объясняется в c2 wiki:

Если вашему приложению необходимо иметь дело с базой данных или другим приложением, модель которого нежелательна или неприменима к модели, которую вы хотите в своем собственном приложении, используйте AnticorruptionLayer для перевода в / из этой и вашей модели.

Пример примечания намеренно сделан простым и сжатым для краткости пояснения.

Если у вас есть большой беспорядок API, чтобы покрыть антикоррупционный уровень, применяется тот же подход: во-первых, убедитесь, что ваш «основной код» не имеет прямого доступа к поврежденным материалам, а во-вторых, представьте его таким образом, который более удобно в вашем контексте использования.

Когда «масштабируете» свой слой за пределы упрощенного примера, приведенного выше, учтите, что сделать ваш API удобным не обязательно тривиальная задача. Инвестируйте усилия, чтобы правильно спроектировать свой слой , проверьте его предполагаемое использование с помощью модульных тестов и т. Д.

Другими словами, убедитесь, что ваш API действительно является улучшением по сравнению с тем, который он скрывает, убедитесь, что вы не просто добавили еще один уровень коррупции.


Для полноты заметим тонкое, но важное различие между этим и связанными паттернами Adapter и Facade . Как видно из его названия, антикоррупционный уровень предполагает, что базовый API имеет проблемы с качеством («поврежден») и намеревается обеспечить защиту упомянутых проблем.

Вы можете думать об этом следующим образом: если вы можете доказать, что дизайнеру библиотеки было бы лучше раскрыть его функциональность Reasonableвместо Messy, это означало бы, что вы работаете над антикоррупционным слоем, выполняете их работу, исправляете их ошибки проектирования.

В отличие от этого, Adapter и Facade не делают предположений о качестве основного дизайна. Они могут быть применены к API, который хорошо разработан с самого начала, просто адаптируя его под ваши конкретные потребности.

На самом деле, было бы даже более продуктивно предположить, что такие шаблоны, как Adapter и Facade, ожидают, что базовый код будет хорошо спроектирован. Вы можете думать об этом так: хорошо разработанный код не должен быть слишком сложным для настройки для конкретного случая использования. Если окажется, что разработка вашего адаптера требует больше усилий, чем ожидалось, это может указывать на то, что лежащий в основе код, ну, как-то «поврежден». В этом случае вы можете рассмотреть возможность разделения работы на отдельные этапы: сначала создайте антикоррупционный слой для правильного представления базового API, а затем создайте свой адаптер / фасад поверх этого уровня защиты.


1
Как это масштабируется, если существует целая структура зависимых классов API? Это все еще более управляемо, чем уровень, от которого он защищает остальную часть приложения?
известноасиля

1
@Knownasilya это очень хороший вопрос, ответ расширился, чтобы ответить на это
комнат

4
In other words, make sure that your API is indeed an improvement over one it hides, make sure that you don't just introduce another layer of corruption.Весь этот раздел достоин жирного тега.
Лилиенталь

19
Антикоррупционные уровни не имеют ничего общего с API низкого качества. Они имеют дело с концептуальными несоответствиями, адаптацией доменов, которые мы могли бы использовать, только «повреждая» наш код в области, которые мы могли бы использовать более легко.
Ян Фэрман

8
Ян Фэрман понял это правильно, а автор этого ответа определенно - нет. Если вы перейдете к источнику концепции (книга DDD), вы обнаружите, по крайней мере, две вещи, которые противоречат этому ответу: 1) создан антикоррупционный слой, чтобы не повредить новую модель домена, которую мы разрабатываем с элементами из модели существующей внешней системы; дело не в том, что другая система «повреждена», на самом деле она может быть очень хорошей и хорошо спроектированной; 2) антикоррупционный слой обычно содержит несколько классов, часто включая Фасады и Адаптеры , а также Сервисы .
Rogério

41

Процитирую другой источник:

Создайте изолирующий слой, чтобы предоставить клиентам функциональность с точки зрения их собственной модели домена. Уровень взаимодействует с другой системой через свой существующий интерфейс, практически не требуя модификации другой системы. Внутренне, слой перемещается в обоих направлениях по мере необходимости между двумя моделями.

Эрик Эванс, Дизайн, управляемый доменом, 16-я печать, страница 365

Самое главное, что на каждой стороне антикоррупционного уровня используются разные термины. Я когда-то работал над системой транспортной логистики. Туры должны были быть запланированы. Вы должны были оборудовать автомобиль в депо, доехать до различных мест обслуживания клиентов и обслуживать их, а также посетить другие места, например, остановку в баке. Но на более высоком уровне это было все о планировании задач. Поэтому имело смысл отделить более общие термины планирования задач от очень специфических логистических условий транспортировки.

Таким образом, изоляция антикоррупционных слоев заключается не только в защите вас от грязного кода, но и в том, чтобы отделить разные домены и обеспечить их разделение в будущем.


6
Это очень важно! ACL предназначен не только для использования с кодом Messy, но и как средство связи между ограниченными контекстами. Он переводится из одного контекста в другой, так что данные в каждом контексте отражают язык и то, как этот контекст думает и говорит о данных.
Дидье А.

29

адаптер

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

Пример:

У вас есть объект, который хочет Car, но у вас есть только класс 4WheelVehicle, поэтому вы создаете CarBuiltUsing4WheelVehicle и используете его как свой автомобиль.

Фасад

Когда у вас сложный / запутанный / гигантский API, и вы хотите сделать его проще / понятнее / меньше. Вы создадите Фасад, чтобы скрыть сложность / путаницу / дополнительные возможности и только выставить новый простой / понятный / маленький API.

Пример:

Вы используете библиотеку, которая имеет 100 методов, и для выполнения определенной задачи вам нужно выполнить множество инициализаций, подключений, открытий / закрытий, просто чтобы наконец иметь возможность делать то, что вы хотели, и все, что вам нужно, - это 1 особенность все 50, которые может делать библиотека, поэтому вы создаете Фасад, в котором есть только метод для той функции, которая вам нужна, и которая выполняет всю инициализацию, очистку и т. д. за вас.

Антикоррупционный слой

Если у вас есть система, которая находится за пределами вашего домена, но ваши бизнес-потребности требуют, чтобы вы работали с этим другим доменом. Вы не хотите вводить этот другой домен в свой собственный, поэтому портите его, чтобы перенести концепцию своего домена в этот другой домен и наоборот.

Пример:

Одна система просматривает клиента, имеющего имя и список строк, по одной для каждой транзакции. Вы рассматриваете Профили как отдельные классы, имеющие имя, а Транзакции как отдельные классы со строкой, а Заказчик - как Профиль и коллекцию Транзакций.

Таким образом, вы создаете слой ACL, который позволит переводить между вашим клиентом и клиентом другой системы. Таким образом, вам никогда не придется использовать клиента другой системы, вам просто нужно сказать ACL: «дайте мне клиента с профилем X, а ACL скажет другой системе присвоить ему клиента с именем X.name и вернет его». Вы клиент с профилем X.

====================

Все три относительно похожи, потому что все они являются паттернами косвенности. Но они касаются разных структур, классов / объектов, API-интерфейсов и модулей / подсистем. Вы могли бы объединить их все, если вам нужно. Подсистема имеет сложный API, поэтому вы создаете для нее FACADE, она использует другую модель, поэтому для каждого представления данных, которое не соответствует вашей модели, вы должны перевести эти данные обратно в то, как вы их моделируете. Наконец, возможно, интерфейсы также несовместимы, поэтому вы должны использовать АДАПТЕРЫ для адаптации от одного к другому.


12

Многие ответы здесь говорят о том, что списки ACL "не просто" для обертывания грязного кода. Я бы пошел дальше и сказал, что они вовсе не об этом, и если они это сделают, то это побочная выгода.

Антикоррупционный уровень предназначен для отображения одного домена на другой, так что службы, использующие второй домен, не должны быть «повреждены» концепциями первого. ACL для моделей предметной области - то же самое, что адаптеры для классов, это просто происходит на другом уровне. Адаптер, пожалуй, является наиболее важным шаблоном проектирования - я использую его все время - но судить обернутый класс как беспорядочный или нет, не имеет значения. Это то, что есть, мне просто нужен другой интерфейс.

Сосредоточение внимания на беспорядке вводит в заблуждение и упускает суть сути DDD. ACL предназначены для решения концептуальных несоответствий, а не низкого качества.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.