Проектирование архитектуры классов с различной логикой в разных местах?
Привет, читающим.
Заголовок вопроса немного непонятный, сейчас объясню подробнее.
Есть класс Bullet. У него много разных методов связанных с разными свойствами пули. Возможная траектория падения, определенная логика попадания, определенное поведение в определенный момент времени, разное возможное реагирование на другие пули. И каждое такое свойство довольно сильно может различаться от класса к классу. К сожалению, я сделал все через наследование, т.е. если класс хотел изменить 2 свойства, то он наследовал от главного и изменял их.
После разростания архитектуры появилось довольно много разновидностей Bullet и тут стала очевидна проблема такого подхода. Допустим MagicBullet наследует от Bullet и изменяет логику попадания и взрыва. Есть еще класс SuperBullet наследующий от Bullet и изменяющий только траекторию. А теперь мне потребовался класс, в котором я хочу логику попадания из MagicBullet и логику траектории из SuperBullet. Возникает проблема дублирования кода, ибо Java не поддерживает множественного наследования.
Вопрос такой, как бы должна была выглядеть архитектура в таком случае? Подвопрос — как будет наиболее безболезненно исправить текущую архитектуру?
По поводу первого вопроса у меня пока есть 2 варианта:
1. Использовать стратегии для каждого из отдельных свойств. Вроде бы вариант не плохой, однако он сильно ограничивает логику тем, что по-идее, каждая из стратегий не должна ничего знать о других стратегиях, а часто случается так, что 2 измененных свойства находятся в тесной связи и возможные связи также могут отличаться от случая к случаю.
2. Использовать один класс Bullet и много разных декораторов. Однако, опять же остается вопрос связи разных свойств.
Если вы хотите, чтобы наследники класса были независимыми, вам придется сделать их независимыми, даже нарушая DRY.
Если у вас нельзя иерархически выделить подтипы класса Bullet, из которых уже можно сделать потомков с необходимыми свойствами (т.е. сделать, например ExplosiveBullet с разрывом пули и MagicExplosiveBullet, SniperExplosiveBullet, etc — уже с конкретными реализациями), то вам тут никак на Java красиво не выкрутиться.
Если вам просто очень необходимо уйти от текущей реализации, но избавиться от дублирования кода, можете использовать паттерн Mixin, вроде я видел реализацию на Java.
Выделить специфичное поведение для каждого аспекта в отдельные классы (траектории в одну группу классов, логику попадания в другую, и т.д.), а в классах наследниках bullet просто использовать логику из них.