Короче говоря, всякий раз, когда вы используете «new», вы тесно связываете класс, содержащий этот код, с создаваемым объектом; чтобы создать экземпляр одного из этих объектов, класс, выполняющий создание экземпляра, должен знать о конкретном классе, который создается. Итак, при использовании «new» вы должны подумать, является ли класс, в который вы помещаете экземпляр, «хорошим» местом для этих знаний, и вы готовы внести изменения в эту область, если форма объект должен был измениться.
Тесной связи, то есть объекта, обладающего знаниями другого конкретного класса, не всегда следует избегать; на каком-то уровне что-то, КУДА-ТО, должно знать, как создать этот объект, даже если все остальное имеет дело с объектом, получив его копию откуда-то еще. Однако, когда создаваемый класс изменяется, любой класс, который знает о конкретной реализации этого класса, должен быть обновлен, чтобы правильно обрабатывать изменения этого класса.
Вопрос, который вы всегда должны задавать: «Будет ли этот класс знать, как создать этот другой класс, как ответственность при обслуживании приложения?» Обе основные методологии проектирования (SOLID и GRASP) обычно отвечают «да» по несколько разным причинам. Тем не менее, они являются только методологиями, и оба имеют крайнее ограничение, что они не были сформулированы на основе знания вашей уникальной программы. Таким образом, они могут ошибиться только на стороне предостережения и предположить, что любая точка жесткой связи ВСЕГДА вызовет у вас проблему, связанную с внесением изменений в одну или обе стороны этого пункта. Вы должны принять окончательное решение, зная три вещи; лучшая теоретическая практика (которая заключается в том, чтобы все объединить, потому что все может измениться); стоимость внедрения теоретической передовой практики (которая может включать в себя несколько новых уровней абстракции, которые облегчат один тип изменений, мешая другому); и реальная вероятность того, что тип изменений, которые вы ожидаете, когда-либо будет необходим.
Некоторые общие рекомендации:
Избегайте тесной связи между библиотеками скомпилированного кода. Интерфейс между DLL (или EXE и его DLL) является основным местом, где тесная связь будет представлять собой недостаток. Если вы вносите изменения в класс A в DLL X, а класс B в основном EXE-файле знает о классе A, вам придется перекомпилировать и выпустить оба двоичных файла. В пределах одного двоичного файла более жесткое соединение обычно более допустимо, поскольку весь двоичный файл должен быть перестроен для любого изменения в любом случае. Иногда необходимость перестраивать несколько двоичных файлов неизбежна, но вы должны структурировать свой код таким образом, чтобы избежать его там, где это возможно, особенно в ситуациях, когда пропускная способность слишком высока (например, развертывание мобильных приложений; добавление новой библиотеки DLL в обновление намного дешевле). чем пихать всю программу).
Избегайте тесной связи между основными «логическими центрами» вашей программы. Вы можете думать о хорошо структурированной программе, состоящей из горизонтальных и вертикальных срезов. Горизонтальные срезы могут быть традиционными уровнями приложения, такими как пользовательский интерфейс, контроллер, домен, DAO, данные; вертикальные срезы могут быть определены для отдельных окон или представлений, или для отдельных «пользовательских историй» (например, создание новой записи некоторого базового типа). При выполнении вызова, который перемещается вверх, вниз, влево или вправо в хорошо структурированной системе, вы должны, как правило, абстрагировать указанный вызов. Например, когда валидация требует извлечения данных, она не должна иметь прямого доступа к БД, а должна вызывать интерфейс для извлечения данных, который поддерживается фактическим объектом, который знает, как это сделать. Когда некоторый элемент управления пользовательского интерфейса должен выполнить расширенную логику, включающую другое окно он должен абстрагироваться от запуска этой логики через событие и / или обратный вызов; ему не нужно знать, что будет сделано в результате, что позволит вам изменить то, что будет сделано, без изменения элемента управления, который его запускает.
В любом случае, подумайте, насколько легко или сложно будет сделать изменение, и насколько вероятно будет упомянутое изменение. Если объект, который вы создаете, когда-либо использовался только из одного места, и вы не предвидите, что это изменение, то жесткая связь, как правило, более допустима и может даже превзойти в этой ситуации слабую связь. Слабая связь требует абстракции, которая является дополнительным уровнем, который предотвращает изменение зависимых объектов, когда реализация зависимости должна измениться. Однако если сам интерфейс должен измениться (добавление нового вызова метода или добавление параметра к существующему вызову метода), то интерфейс фактически увеличивает объем работы, необходимый для внесения изменения. Вы должны взвесить вероятность различных типов изменений, влияющих на дизайн,