Сложны ли зависимости круговых классов от стиля стиля кодирования?
Сложны ли зависимости циклического класса от стиля стиля кодирования?
Пример:
В приложении базы данных есть два класса: одна инкапсуляция информации об одной базе данных (DBInfo
) и один класс, который может создать соединение с базой данных. (ConnFactory
)
DBInfo
имеет метод getConnection
, который использует ConnFactory
для создания соединения. Но для этого ConnFactory
нужен объект DBInfo
.
Подобно этому: (Любые стили кодирования не учитываются для удобства чтения)
class DBInfo {
String name;
String connectionUrl;
Connection getConnection() {
return ConnFactory.getConnection(this);
}
}
class ConnFactory {
Connection getConnection(DBInfo toWhat) {
return new Connection(toWhat.connectionUrl);
}
}
Мои коллеги утверждают, что это плохая практика, и было бы лучше, если бы было только одно направление зависимостей и не было круговых, как здесь.
Является ли эта плохая практика, анти-шаблон или запах кода? Есть ли недостатки?
Ответы
Ответ 1
В общем, я бы назвал круговые зависимости кодовым запахом. Обратите внимание, что термин "Code Smell" в основном указывает на то, что "вот фрагмент кода, который требует особого внимания, и, вероятно, получит выгоду от редизайна".
В большинстве случаев я бы решительно рассмотрел проект, где круговая зависимость не нужна, но в редких случаях это может быть хорошо.
В вашем примере ConnFactory кажется излишним, но это может быть потому, что ваш пример был обрезан. Мне кажется, однако, что логика создания соединения была бы лучше, если бы она была перенесена в класс DBInfo. Когда у вас уже есть класс, содержащий данные о базе данных, кажется естественным, что он несет ответственность за создание соединения с этой базой данных.
Ответ 2
Да, вообще говоря, круговые зависимости плохие, хотя и не всегда злые. Проблемы с круговыми зависимостями включают жесткую связь, взаимозависимые модули и вообще эффект домино, когда изменения в одном модуле распространяются на другие модули.
Тем не менее, ваш код нарушает принцип единой ответственности, поскольку DBInfo
не только хранит информацию о базе данных, но также отвечает за получение объектов Connection
. Удалите эту конкретную функциональность отдельному классу, и все будет хорошо.
Ответ 3
Не обязательно
Я не думаю, что круговые зависимости на уровне детализации класса плохие. Я не вижу проблемы, если два, три или, возможно, четыре класса взаимозависимы. (Я не говорю, что это то, что вы хотите, но в некоторых случаях это может быть хорошо).
Это есть проблема, если у вас есть взаимная зависимость на уровне пакета или модуля по всем причинам, упомянутым выше и ниже.
Ответ 4
Этот код работает только в том случае, если ConnFactory.getConnection()
является статическим. Лучшим решением было бы сделать getConnection()
метод экземпляра ConnFactory
. Тогда ваш DBInfo может принимать ConnFactory
в качестве аргумента (возможно, в конструкторе, если у вас есть перегруженный конструктор). Тем не менее, я думаю, что использование статического метода для этого случая является скорее неправильной практикой, чем круговой ссылкой.
Если бы вы пошли по этому маршруту, я бы также создал интерфейс IConnFactory
, с которым будет взаимодействовать DBInfo
, и что ConnFactory
будет реализовывать. Тогда нет круговой ссылки - как DBInfo
, так и ConnFactory
будет зависеть от IConnFactory
, которая не зависит от них.
Ответ 5
Все, что я знаю, это то, что круговые зависимости могут стать немного проблемой, когда вы начинаете использовать платформу Injection Dependency, такую как Structure Map. Большинство из этих фреймворков имеют проблемы с обработкой циклических зависимостей, иногда приводя к исключению (pardon pun:-)) Поэтому я стараюсь избегать этого, если это абсолютно необходимо, и его нельзя избежать.
Ответ 6
Как насчет двунаправленного отношения "один ко многим", которое является обычным случаем в любом приложении с использованием уровня ORM? Разве это не круговая зависимость?
Является ли это плохим/кодовым запахом?
Ответ 7
Круговые зависимости плохи, потому что:
- две зависимости более одного
- вы не можете инкрементно тестировать (без издевательства над одним из них, что было бы глупо для маленьких, тесно связанных вещей).
Вы можете сделать все с интерфейсами, чтобы разорвать круговую зависимость, если это необходимо, но простое минимальное решение - просто сделать DBInfo вложенным классом ConnFactory. Единица, которая ссылается сама по себе, не является круговой.