Как решить круговые зависимости пакета

11

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

Я помню, как где-то узнал, что граф зависимостей пакетов не должен иметь циклов, но я не знаю, как решить следующую проблему: Figureнаходится в пакете figure, Layoutнаходится в пакете layout, Layoutтребует фигуры для выполнения макета, поэтому пакет layoutзависит от пакета figure. Но с другой стороны, a Figureможет содержать Figureвнутри себя другие s, имеющие свои собственные Layout, что делает пакет figureзависимым от пакета layout.

У меня есть некоторые решения, такие как создание Containerинтерфейса, который Figureреализует и положить его в Layoutпакет. Это хорошее решение? Есть ли другие возможности?

благодаря

vainolo
источник
Именно модули (например, разные банки) не могут иметь круговых зависимостей. Пакеты CAN и часто имеют циклические зависимости, если они принадлежат одному модулю.
января
@lorus Так что это не проблема дизайна?
Vainolo
2
Нет это не так. Пакеты, как правило, являются просто пространством имен. Это может измениться, только если они используются для чего-то другого, например, для изменения видимости их содержимого в среде OSGi. Не беспокойся иначе.
Форус
1
Обратите внимание, что многие органы власти осуждают циклические зависимости, а иногда и по уважительной причине, но перед тем, как приступить к слепому рефакторингу, вам следует убедиться, что одна из этих причин действительно относится к вам. Если структура пакета не доставляет вам проблем, и вы не можете с чистой совестью понять, почему это произойдет в будущем, не изменяйте что-то столь фундаментальное, чтобы удовлетворить абстрактные архитектурные ценности.
Килиан Фот

Ответы:

9

Вы должны думать об инверсии контроля

Вы в основном определяете интерфейс для вашего, Layoutкоторый расположен где-то рядом с вашим классом Layout в собственном пакете, так что у вас будет пакет реализации и пакет общедоступного интерфейса - например, вызовите его Layoutable(я не знаю, правильный ли это английский). Теперь - Layout будет реализовывать не этот интерфейс, а Figureкласс. Точно так же вы бы создали интерфейс для Figure, Drawableнапример.

Так

my.public.package.Layoutable
my.implementation.package.Layout
my.public.package.Drawable
my.implementation.package.Figure

Теперь - Рисунок реализует Layoutable и, таким образом, может использоваться Layout и (пока я не уверен, что это именно то, что вы хотели) - Layout реализует Drawable и может быть нарисован на рисунке. Дело в том, что класс, который предоставляет некоторый сервис, делает его доступным через интерфейс (здесь: Layout и Layoutable) - класс, который хочет использовать этот сервис, должен реализовать интерфейс.

Тогда у вас будет что-то вроде объекта-создателя, который связывает их вместе. Так что создатель имел бы зависимость Layoutкак от Figure, так Layoutи от Figureсебя , но и сам был бы независимым.

Это грубая идея.

Отличным источником решения этих проблем является книга Кирка Кнорншильда « Архитектура приложений Java ».

michael_s
источник
Разве это не то же самое, что Containerинтерфейс, предложенный в вопросе?
vaughandroid
Да - и нет - я бы не положил их в одну упаковку, как я сказал. И не было много теории за этим. И в этом случае недостаточно сделать это с одной стороны, вам придется делать это с обеих сторон. Хорошо?
michael_s
К сожалению, я упустил немного в первоначальном вопросе о том, чтобы Containerпойти в той же упаковке, что и Layout. Это не сработает, а ваше решение будет.
vaughandroid
ах - хорошо - я, кажется, пропустил часть с Контейнером, хотя, когда я взламывал - должен был назвать его Контейнером;)
michael_s
0

Мне не очень понятно, что это Figureтакое, но, возможно, оно должно быть в той же упаковке, что и Layout?

Ваше предлагаемое Containerинтерфейсное решение не будет работать - если вы не поместите Containerинтерфейс в 3-й пакет, у вас все равно будет циклическая зависимость между двумя пакетами. Смотрите ответ michael_s для чего-то, что будет работать.

Другое дело, как уже упоминали другие, - это, вероятно, никогда не будет проблемой. Вы только собираетесь столкнуться с проблемами в будущем , если Figureи Layoutхотят быть в отдельных модулях . Вы можете справиться с этим, если и когда это станет необходимым, но, учитывая, что эти два класса кажутся довольно тесно связанными, это кажется маловероятным.

vaughandroid
источник