Правильный ли дизайн с использованием принципа инверсии зависимостей между модулями?
Я понимаю инверсию зависимостей при работе внутри одного модуля, но я хотел бы также применить ее, когда у меня есть межмодульная зависимость. На следующих диаграммах у меня есть существующее приложение, и мне нужно реализовать некоторые новые требования к службам справочных данных. Я думал, что создам новую флягу (потенциально автономный сервис в будущем). На первом рисунке показан нормальный подход к таким вещам в прошлом. У jar referencedataservices есть интерфейс, который приложение будет использовать для его вызова.
На втором рисунке показана моя попытка использовать DIP, теперь приложение владеет своей абстракцией, поэтому оно не подлежит изменению только потому, что изменяется служба справочных данных. Это, кажется, неправильный дизайн, потому что он создает круговую зависимость. MyApp зависит от Jar ссылочных сервисов, а Jar ссылочных сервисов зависит от MyApp.
Таким образом, третья фигура возвращается к более нормальной зависимости, создавая дополнительный уровень абстракции. Я прав? Или это действительно не то, для чего предназначен DIP? Интересно услышать о других подходах или советах.
2 ответа
Второй пример находится на правильном пути, отделяя реализацию от ее абстракции. Для достижения модульности конкретный класс не должен находиться в том же пакете (модуле), что и его абстрактный интерфейс.
Ошибка во втором примере заключается в том, что клиент владеет абстракцией, а служба владеет реализацией. Эти две роли необходимо поменять местами: собственные интерфейсы служб; клиенты собственных реализаций. Таким образом, сервис представляет контракт (API) для реализации клиентом. Сервис гарантирует взаимодействие с любым клиентом, который придерживается своего API. С точки зрения инверсии зависимостей, клиент вводит зависимость в сервис.
Кирк К. является авторитетом в модульности в Java. У него был блог, который в итоге превратился в книгу на эту тему. Кажется, его блог сейчас отсутствует, но я смог найти его в Wayback Machine. Я думаю, что вы были бы особенно заинтересованы в серии из четырех частей под названием Прикладная модульность. С точки зрения других подходов или альтернатив DIP, взгляните на Fun With Modules, который охватывает три из них.
Во втором подходе, который вы представили, если вы двигаетесь RefDataSvc
абстракция в отдельный пакет, вы нарушаете цикл и referencedataservices
пакет использовать только пакет с RefDataSvc
абстракция.
Другой код кроме корня композиции в MyApp
пакет должен зависеть также от RefDataSvc
, В Composition Root вашего приложения вы должны затем составить все зависимости, которые необходимы в вашем приложении.