Агрегация или наследование?
Агрегация или наследование?
Евгений Каратаев
И
снова о проектировании классов. Больная тема и место применения множества
трюков. Большинство программистов используют трюки по-разному. Видимо, есть три
способа их применения - 1) неосознанно, 2) осознанно, но с затруднениями при
выборе способа и 3) осознанно и, более того, трюки вычисляются.
Рассмотрим
вопрос выбора пути при решении задачи типа "добавление новой
функциональности". Имеется модуль в виде набора классов, который по
функциональности частично подходит к тому, что надо получить. Имеется задача
добавить в модуль некую функциональность. Имеется нежелание много работать и
иметь в последующем с полученным кодом проблемы. При желании в эти условия задачи
можно, полагаю, вписать практически любую программерскую задачу.
Рассмотрим
выбор между двумя вариантами действий. Первый вариант - взять имеющийся класс,
максимально подходящий к требуемому и изменить его путем модификации без
получения нового класса. Скажем, поправить несколько функций или добавить
несколько членов класса. Второй вариант - составить новый класс, унаследованный
от максимально подходящего к требуемой функциональности и дописать к наследнику
что ему не хватает или переопределить часть виртуальных функций базового.
Первый вариант договоримся называть агрегированием, а второй - наследованием.
Рассмотрим подробнее оба варианта, абстрагируясь от выбора конкретного языка
программирования и содержания классов.
При
агрегации мы не получаем нового класса и для обеих задач, старой и новой,
используем один и тот же класс. Агрегацию мы можем получить не только как
способ решить новую задачу, но и как способ исправить ошибки в старой задаче,
поскольку исправления кода автоматически влияют на старую задачу. При агрегации
к классу добавляется одно или два поля, благодаря которым и происходит
различение старой и новой функциональности. А именно по значению этих полей.
Например, добавленное поле имеет смысл номера версии, в зависимости от значения
которой в модифицированном классе различается поведение нескольких функций.
Этим способом мы можем избежать рутины с большим количеством модификаций
задачи. Что является типичным признаком современного проекта. Добавляем поле, и
при изменениях в спецификации корректируем поведение нескольких функций.
Переопределять виртуальные функции по понятным причинам нет необходимости.
При
наследовании мы получаем новый класс. Возможно, несколько. Новая
функциональность реализуется исключительно в новом классе и имеющийся код этого
никак не замечает и продолжает работать (надеюсь, без ошибок ;). В наследнике
переопределяем одну или несколько виртуальных функций и при необходимости того
добавляем поля данных. Примеры, как это делать, программисты сами могут
привести из своей практики.
Сведем
сравнительные различия в таблицу.
Вид различия
Похожие работы на - Агрегация или наследование?
|