Есть ли способ избежать круговых зависимостей, кроме смешивания модулей, в расположении как это (это - шахматное приложение),
Длинное описание:
Gui
модуль, который импортирует a ChessWidget
модуль;ChessWidget
просто переносится ChessWorld
модуль и импорт CellButton
;CellButton
модуль импортирует модуль Cell
;ChessWorld
импорт модуля Board
(для представления его) и Players
(чтобы уведомить их и выбрать их перемещения);Board
модуль импортирует модуль Piece
;Piece
модуль импортирует модуль Player
;И ВОТ ПРОБЛЕМА:
Player
модуль должен знать о других плеерах и плате, таким образом импортируя ChessWorld
!
Краткое описание:
World
модуль должен знать о Player
модуль (даже косвенно Board
/Piece
) и Player
потребность знать о World
.
Справка очень ценится.
PS: то, не потому что я не могу использовать круговые зависимости, но потому что они являются злыми.
Следуйте принципу Инверсии зависимости : введите интерфейс, который ChessWorld
реализует и от которого зависит Игрок
-- и/или тот, который реализует Игрок
и от которого зависит Часть
(либо то, либо другое может быть уместно в зависимости от подробностей о природе зависимости). Это часто сочетается с Впрыском зависимости , и, если иждивенцу необходимо динамически инстанцировать ряд экземпляров депендеев, с Фабричным ДПс.
Рассмотрим, что на самом деле нужно каждому объекту, а не то, что ему просто необходимо в данный момент.
Кусок, вероятно, не должен знать об Игроке - то, что он должен знать, это то, что он может посылать обновления.
Итак, например, создадим интерфейс, представляющий "PieceMessageListener" или что-то подобное, и пусть Игрок реализует это. Теперь оба вида конкреций зависят от абстракции (переходим к правилу "конкреции должны зависеть от абстракций, абстракции не должны зависеть от конкреций")
.Я засуну руку сюда и скажу... IMHO вы, возможно, перепроектировали это.
Почему фигура должна обладать знаниями об игроке? Фигура в шахматах либо черная, либо белая, независимо от того, кто ее контролирует (играет).
Вы упоминаете "модуль игрока" и "модуль фигуры" - почему это отдельные модули? Почему они не являются просто классами данных (доменными объектами) вместе в одном модуле?
Если я переусердствовал с анализом или не понял, как вы построили свою игру, то обязательно проигнорируйте то, что я сказал. ОТОХ, может быть, я правильно прочитал?
Я думаю, что запах циклической зависимости скорее указывает на архитектурную / дизайнерскую проблему, которая не должна ' Это может быть решено с помощью DI, позднего ограничения, слабой связи или любой другой формы дополнительного уровня абстракции. Хотя все они являются очень хорошими механизмами, но не решают стоящую за ними проблему.
Вкратце: я думаю, что ChessWorld несет слишком много обязанностей . Если вы разделите их, вы, вероятно, обнаружите, что зависимости - это обязанности, которые лучше подходят для отдельного модуля.
Длинное пояснение: я попытаюсь привести пример того, как бы я реорганизовал его, хотя это сложно, потому что я не совсем разбираюсь в предметной области.
ПРИМЕЧАНИЕ. Я не знаком с Java, поэтому могу неправильно понять последствия импорта и переноса.
Но, насколько я понимаю, зависимости выглядят примерно так:
Gui <- ChessWidget <- ChessWorld <- CellButton <- Cell
<- Board <- Piece <- Player
<- Players <- ChessWorld
ИМХО, проблема в том, что ChessWorld имеет слишком много разных обязанностей. Ведение списка игроков, вероятно, лучше в отдельном модуле, таком как PlayerList, RegisteredUsers или OnlineUsers или что-то подобное. После этого рефакторинга ваши зависимости изменятся следующим образом:
Gui <- ChessWidget <- ChessWorld <- CellButton <- Cell
<- Board <- Piece <- Player
<- Playerlist <- Player
PlayerList, вероятно, будет чем-то, что у вас будет в модуле player. Теперь Chessworld зависит от модуля игрока, а не от другого.
Я не уверен, что это полностью соответствует вашим намерениям, но мне очень интересно это обсудить, поэтому, пожалуйста, прокомментируйте.