Чем плохи длинные цепочки наследований? И так, ситуация: Мы разрабатываем клиент-серверные приложения, постоянно работаем с большим количеством сущностей и планируем использовать автогенерацию кода на основе описаний объектов. Стандартные инструменты apache thrift \ protobuf нам не подошли, поэтому мы планируем писать свой велосипед. Сгенерированный код предполагает, что в него не вносят ручных модификаций, а значит никакой логики там быть не может по определению. Наши сгенерированные классы- это фактически набор полей(property), заданных типов, с геттерами\сеттерами и методами сериализации\десериализации. В стандартном случае у нас сгенерированные объекты имеют какую-то цепочку наследования C_GENERATED <- B_GENERATED A_GENERATED Мы легко можем дальше объявить свой C_CUSTOM <- C_GENERATED и добавить нужную нам логику. Но, как поступать в случае, если логику нужно объявить в промежуточном, сгенерированном классе, например в B_GENERATED(у нас может быть еще несколько классов, наследуемых от B_GENERATED вроде CA_GENERATED<- B_GENERATED и логику требуется внести в родительский к ним класс)? Есть два пути решения: 1) генерировать цепочку наследования с промежуточными кастомными классами: C_CUSTOM <- C_GEN <-B_CUSTOM <- B_GEN <- A_CUSTOM <- A_GEN 2) генерировать симметричную цепочку наследования C_CUSTOM <- B_CUSTOM <- A_CUSTOM, и передавать в кастомные объекты ссылку на соответствующий сгенерированный объект. Примерно это может выглядеть так:class C_CUSTOM extends B_CUSTOM { var _c; override function setData(C_GEN c) { parent::setData(c); _c=c } } class B_CUSTOM extends A_CUSTOM { var _b; function inc(int i) { _b.aaa+=i; }
override function setData(B_GEN b) { parent::setData(b); _b=b; } } c_custom=new C_CUSTOM(); c_custom.setData(c_gen); c_custom.inc(10); В 1 случае - у нас, единственный минус - это длинные цепочки наследования (х2 от исходного) Во 2 случае - помимо общей громоздкости - нам, например - необходимо дополнительно выполнять кастинг исходного объекта до родителя перемещаясь по цепочке Собственно вопрос - так ли страшно длинное наследование? Какие минусы из этого реально могут возникнуть? Может есть еще какие-то пути решения? P.s. языко-зависимые "неооп" решения типа множественного наследования или его вариаций в виде mixin\trait использовать точно не будем\не можем\не хотим.
Длинные цепочки наследования могут привести к следующим проблемам:
Усложнение понимания кода: Чем длиннее цепочка наследования, тем сложнее становится отслеживать, откуда все методы и свойства в производных классах наследовались. Это может затруднить понимание и поддержку кода.
Увеличение вероятности возникновения ошибок: При длинных цепочках наследования есть риск внесения изменений, которые могут негативно отразиться на других классах в цепочке.
Проблемы с производительностью: Чем больше классов в цепочке наследования, тем больше времени может потребоваться для обращения к методам и свойств в объектах.
Проблемы с тестированием: Длинные цепочки наследования могут усложнить написание и проведение тестов, так как необходимо учитывать влияние всех классов в цепочке наследования.
Если вы столкнулись с необходимостью добавления логики в сгенерированные классы в промежуточных уровнях наследования, то может быть полезно рассмотреть другие подходы, например, использование композиции вместо наследования. Вы можете создать промежуточные классы, которые будут содержать ссылки на другие классы, а не наследовать их, что может сделать вашу структуру более гибкой и понятной.
Также, вы можете рассмотреть возможность использования шаблонов проектирования, таких как декоратор или стратегия, чтобы добавить функциональность в сгенерированные классы без увеличения цепочки наследования.
В любом случае, важно оценить все плюсы и минусы каждого подхода и выбрать наиболее подходящий для вашего проекта.
Длинные цепочки наследования могут привести к следующим проблемам:
Усложнение понимания кода: Чем длиннее цепочка наследования, тем сложнее становится отслеживать, откуда все методы и свойства в производных классах наследовались. Это может затруднить понимание и поддержку кода.
Увеличение вероятности возникновения ошибок: При длинных цепочках наследования есть риск внесения изменений, которые могут негативно отразиться на других классах в цепочке.
Проблемы с производительностью: Чем больше классов в цепочке наследования, тем больше времени может потребоваться для обращения к методам и свойств в объектах.
Проблемы с тестированием: Длинные цепочки наследования могут усложнить написание и проведение тестов, так как необходимо учитывать влияние всех классов в цепочке наследования.
Если вы столкнулись с необходимостью добавления логики в сгенерированные классы в промежуточных уровнях наследования, то может быть полезно рассмотреть другие подходы, например, использование композиции вместо наследования. Вы можете создать промежуточные классы, которые будут содержать ссылки на другие классы, а не наследовать их, что может сделать вашу структуру более гибкой и понятной.
Также, вы можете рассмотреть возможность использования шаблонов проектирования, таких как декоратор или стратегия, чтобы добавить функциональность в сгенерированные классы без увеличения цепочки наследования.
В любом случае, важно оценить все плюсы и минусы каждого подхода и выбрать наиболее подходящий для вашего проекта.