Вы, похоже, боретесь с кодом, который может работать с данным типом, но нельзя доверять для правильной работы с подтипами.Это, вообще говоря, нарушение многих принципов ООП, одним из которых является LSP или Принцип замещения Лискова .
Возможно, вы находитесь в месте, где вы можете рассмотреть шаблон посетителя как способ преодоления этой проблемы.Это очень близко к тому, что у вас уже есть, с некоторыми незначительными изменениями, что хорошо!Приятно, когда шаблоны появляются из вашего кода, а не навязываются ему.
Ваши методы void Receiver
по сути уже являются реализациями посетителей, поэтому давайте переименуем их и создадим интерфейс.
interface IVisitor
{
void Visit(Gamma gamma);
void Visit(Epsilon epsilon);
void Visit(Beta beta);
void Visit(Alpha alpha);
}
Ваш класс, который обрабатывает обработку каждого типа элемента, просто должен реализовать этот интерфейс.
class Visitor : IVisitor
{
public void Visit(Gamma gamma) { Console.WriteLine("Visiting Gamma object"); }
public void Visit(Epsilon epsilon) { Console.WriteLine("Visiting Epsilon object"); }
public void Visit(Beta beta) { Console.WriteLine("Visiting Beta object"); }
public void Visit(Alpha alpha) { Console.WriteLine("Visiting Alpha object"); }
}
Затем пусть каждый тип элемента также реализует простой и общий интерфейс
interface IElement { void Accept(IVisitor visitor); }
class Alpha : IElement
{
public virtual void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
class Beta : Alpha
{
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
// etc.
(Строго говоря, интерфейсы не необходимы , это просто хорошоform.)
И вот, метод двойной диспетчеризации, при котором элемент вызывает метод посетителя , специфичный для его собственного типа , даже если у вас есть ссылка на него через базувведите.
Alpha alpha = new Beta();
IVisitor visitor = new Visitor();
alpha.Accept(visitor);
Если вы правильно его внедрили, вы должны увидеть «Посещение бета-объекта» на экране (или, по вашему мнению, вы должны увидеть желаемое поведение «Приемник»).
Другой вариант, который вы могли бы рассмотреть, - это просто сделать Receiver
виртуальным методом в вашем базовом классе и позволить производным классам переопределять его, и иметь поведение внутри классов, если это имеет смысл для вашей иерархии.Если поведение должно быть внешним, вы могли бы также рассмотреть фабричный подход, который знает, как создать определенный процессор для данного класса.У вас есть много опций, которые не приводят к тому, что ваша программа сходит с ума, если подтип передается методу, ожидающему основание.
Мне требуется нечто необычное.Я хочу иметь возможность передавать объекты Alpha всем методам, но мне не нужны такие методы, как void Receiver (Beta beta);возможность получать объекты типов, которые наследуются от бета-версии (то есть, я хочу, в худшем случае, вызвать исключение, если передан объект Gamma или Epsilon.
Это действительно очень странно. ИЯ не уверен, что вы на самом деле этого хотите. У вас, кажется, иерархия наследования перевернута с ног на голову, где супертипы могут быть заменены производными типами, а не наоборот, и вы должны действительно пересмотретьВы пытаетесь сделать.