При старте небольшого нового проекта появился повод "порефлексировать"
На излюбленную нашу тему - наследования против композиици
Мы тут часто выссказывали идею, что нужно избегать наследования реализации (строить по преимуществу гомогенные иерархии - абстрактный интерфейс->конкретная реализация), реализовывать расширяемость и повторное использование за счет разделения ответственности между многими мелкими классами и их комбинирования.
Сейчас попытался осмыслить, каким образом мне это (неосознанно) удавалось.
У меня сложился стиль реализации (не проектирования) "снизу вверх", от частей к общему.
Сначала проектирую общую архитектуру системы "сверху вниз" - общим планом, какие модули, как они делят ответственность, какие сервисы клиентам предоставляют. Но ОО-проектирование на этом этапе не выполняю.
Далее начинается этап реализации. И вот тут-то уже работаю "снизу вверх". На каждом этапе работы получается такой цикл: пытаюсь найти какую-либо отдельную подзадачу, вспомогательную для других, как можно более мелкую, но обязательно могущую стать повторно используемой. Для этой подзадачи проектирую компактный абстрактный ОО-интерфейс (сразу на Компонентном Паскале). Иногда сразу делаю базовую реализацию, иногда откладываю на потом. Так проделываю со всеми самыми мелкими задачами. Затем начинаю проделывать тоже же самое с задачами более высокого уровня, в их интерфейсах используя коммутацию с ранее разработанными мелкими типами.
И т.д. - до тех пор, пока не сформируется вся запланированная структура системы.
Чем этот подход, как мне кажется, выгодно отличается от принятого ОО-проектирования "сверху вниз"? На каждом этапе мы имеем микрозадачи - и микроинтерфейсы, которые являются практически неделимыми. Нет никакой необходимости (и соблазна) использовать наследование реализации, поскольку повторно используется некоторый конкретный тип целиком, а наследовать отдельные его процедуры не имеет смысла (настолько тип сильно-связанный).
При обычном же способе происходит с точностью до наоборот: сначала вырабатывается ОО-интерфейс для самых высокоуровневых задач, очень трудно отделить в нём главное от второстепенного (трудно даже заставить себя это проделать), все типы получаются жирными, перенасыщенными ответственностью, повторно перепроектировать не хочется - и тянутся длиннющие зависимости по реализации...