У вас есть два подхода к вашей проблеме: один - использовать универсальное программирование (горизонтальный полиморфизм) или атаковать его, используя более традиционную реализацию на основе вертикальной иерархии.
Ваши решения должны основываться на типесходства, которые разделяются между различными типами данных.В случае, если мы можем определить полный и ортогональный контракт, который может работать в любом типе, тогда мы можем легко решить использовать дженерики.
Это, например, случай со списком, словарем и всеми классами в пространстве имен System.Collections.Generic, которые в итоге заменили соответствующие им неуниверсальные аналоги ранних версий .NET.
С другой стороны, опять же из мира .NET мы можем использовать в качестве примера вертикальной иерархии класс UserControl, который наследуется от ContainerControl и служит основой для других элементов управления, специализирующих его поведение с использованием его виртуальных методов....
В большинстве случаев, хотя дизайн вашей иерархии классов включает в себя множество вызовов суждения, которые не всегда определяются детерминистически, поскольку они больше полагаются на ваш опыт и талант разработчика, а не на конкретнуюмодель, которая может быть применена по всем направлениям в любой возможной ситуации ..