Шаблоны следует использовать только там, где они могут быть лучшим решением или помочь в создании хорошего решения (вы согласны?).
Я вижу шаблоны проектирования строго как детали реализации. Если вы документируете свои общедоступные API и программируете эту документацию, в общем случае не имеет значения (или не сильно повлияет на вас), где у вас есть шаблоны проектирования. То есть, вы не говорите: «У меня есть шаблон моста, и я добавлю посетителя поверх него». Вместо этого это «этот класс будет иметь разные реализации в разных операционных системах, поэтому он будет реализован с использованием шаблона моста». Затем, когда вы используете его, вам безразлично, что он реализован в виде моста - потому что вы смотрите на публичный API, а не на шаблон моста.
сколько усилий нужно на самом деле инвестировать в создание слабо связанных, гибких конструкций?
Слабая связь может быть достигнута, следуя простому набору правил. Если вы уважаете их, ваш код будет (более) слабо связан, как вы пишете (т.е. любые усилия уже являются частью процесса разработки).
Среди правил (не исчерпывающий список):
- определяйте свои интерфейсы, думая (или записывая) клиентский код (как будет использоваться класс), а не то, что будет делать класс (то есть дизайн интерфейса, а не реализация)
- "скажи, не спрашивай"
- строить объекты из уже созданных частей
- передать в конструктор фактические объекты, которые вы будете использовать (не фабрики для членов, параметры для фабрики параметров или что-то в этом роде).
- СУХОЙ (если у вас есть две строки, которые появляются в одном и том же порядке в двух местах, извлеките их в отдельную функцию и т. Д.).
- Если создание объекта является более сложной операцией, реализуйте создание промежуточных частей как метод / класс фабрики (т. Е. Не в теле конструктора).
- ЯГНИ (создавайте вещи так, как вам нужно, не раньше).
Эти правила соблюдаются по-разному, в зависимости от языка, методологии разработки, используемой вашей командой (например, TDD), временных ограничений бюджета и так далее.
Например, в Java рекомендуется определить ваш интерфейс как interface
и написать на нем клиентский код (а затем создать экземпляр интерфейса с помощью класса реализации).
В C ++, с другой стороны, у вас нет интерфейсов, поэтому вы можете написать интерфейс только как абстрактный базовый класс; Поскольку в C ++ вы используете наследование только тогда, когда к нему предъявляются строгие требования (и поэтому избегаете ненужных виртуальных функций), вы, вероятно, не будете определять интерфейс отдельно, только заголовок класса).
Те, кто выступает против шаблонов проектирования, говорят, что затраты на использование этих шаблонов часто перевешивают выгоды.
Я думаю, что они делают это неправильно. Если вы пишете слабосвязанный (и СУХОЙ) код, интеграция в него шаблонов проектирования требует минимальных дополнительных усилий. В противном случае вам придется адаптировать свой код для реализации шаблона проектирования.
Если вам нужно внести множество изменений для реализации шаблона проектирования, ваша проблема не в шаблоне проектирования, а в том, что ваша кодовая база является монолитной и тесно связанной. Это плохая / неоптимальная проблема проектирования, а не проблема шаблонов проектирования.
Что я хотел бы знать, так это то, сколько усилий я действительно должен приложить для создания дополнительных уровней абстракции и дизайна, только чтобы мое приложение следовало принципам ОО, таким как слабая связь, программирование интерфейса и т. Д. Стоит ли это действительно Это? Сколько усилий я должен приложить к этому?
Ваши вопросы приводят (неустановленное) предположение, что единственным преимуществом слабой связи является возможность легко реализовывать шаблоны проектирования. Не то.
Среди преимуществ слабой связи:
- рефакторинг и редизайн гибкость
- меньше напрасных усилий
- способность быть свидетелем в суде
- увеличена возможность повторного использования кода
- простота дизайна
- меньше времени, проведенного в отладчике
... и несколько других, которые не приходят мне в голову прямо сейчас.