Я работаю над иерархией классов в моем проекте, и в основном у меня похожая ситуация, как вы описали в своем вопросе.
Допустим, у меня есть базовый тип Object, который является абсолютным корнем всех других классов в моем наборе инструментов.,Поэтому, естественно, все происходит из него напрямую или через его подклассы.Существует общая функциональность, которую должен обеспечивать каждый класс, производный от объекта, но в некоторых листовых классах эффекты мало отличаются от других.Например, каждый объект имеет размер и положение, которые можно изменить с помощью свойств или методов, таких как Position = new Point (10, 10), Width = 15 и т. Д. Но существуют классы, которые должны игнорировать установку свойства или изменять его в соответствии с собственными силами.внутреннее состояниеПодумайте об элементе управления, прикрепленном к левой стороне родительского окна.Вы можете установить свойство Height все, что вам нравится, но оно, как правило, будет игнорироваться, потому что это свойство действительно зависит от высоты элемента управления родительского контейнера (или его высоты ClientArea или чего-либо подобного).
Таким образом, наличие абстрактного класса Object, реализующего базовое общеефункциональность в порядке, пока вы не достигнете точки, где вам нужно "настроить" поведение.Если Object предоставляет защищенный виртуальный метод SetHeight, который вызывается в параметре setter свойства Height, вы можете переопределить его в своем классе DockedControl и разрешить изменение высоты только в том случае, если закрепление установлено на None, в других случаях вы ограничиваете его или полностью игнорируете.
Таким образом, мы счастливы, но теперь у нас есть требование для объекта, который реагирует на события мыши, такие как Click или Hover.Таким образом, мы извлекаем MouseAwareObject из абстрактного класса Object и реализуем события и прочее.
И теперь клиенту нужны стыкуемые объекты с поддержкой мыши.Итак, мы унаследованы от DockableObject и ... хм, что теперь?Если мы можем сделать множественное наследование, мы можем сделать это, но мы сталкиваемся с проблемой алмаза с неоднозначностью дублированного интерфейса, и мы должны иметь дело с этим.У нас может быть два члена типов Dockable и MouseAware в новом классе и внешние вызовы через прокси для обеспечения функциональности.
И последнее, что приходит на ум, - это создать интерфейсы IDockable и IMouseAware и позволить им определять функциональность и добавлять их свободно только к объектам, которые должны обеспечивать конкретное поведение / реализации.
Я думаю, что яразделит мой базовый класс на части и оставит мой Объект с очень ограниченным «базовым» набором свойств и методов и остальной функциональностью, которая фактически необязательна для Объектов как тип, но необходима в конкретных случаях для перехода на интерфейсы, такие как IResizable, IDockable, IMakeAWorldABetterPlaceAbleи т. д. С помощью этого решения можно «прикреплять» поведения к объектно-производным классам без необходимости перетаскивать виртуальные или чисто виртуальные (абстрактные) методы из корневого базового класса вплоть до конечного класса.
ТамКонечно, неудобно реализовывать интерфейсы во всех затронутых классах, но вы всегда можете реализовать некоторые «адаптеры» и просто перенаправлять вызовы к ним.Таким образом, у вас не будет дублированной реализации (в некоторой степени, конечно) и вы не будете связаны между реализацией задачи (изменение размера может означать разные вещи для разных классов) и ожиданием клиентского кода.
Возможно, это не идеальноответьте на ваш вопрос, но, возможно, он намекает вам на собственное решение.