Пусть надо реализовать функцию от двух переменных f(X, Y), где типы X и Y - суть корни деревьев наследования, причем так, чтобы при появлении нового типа X или Y компилятор нам сам подсказывал, что надо дописать. Обычная стандартная задача двойной диспетчеризации :) Не претендуя на всеобщий ее охват, напишу примененный мною метод реализации такого механизма. Добавлю только, что типы X и Y абстрактные.
Итак, в типе
Определяю новый тип (interface) YVisitor:
public interface YVisitor
{
void visitY1( Y1 y );
void visitY2( Y1 y );
}
помещаю туда методы про те потомки типа Y, которые вспоминаются.
В тип Y помещаю абстрактный метод:
public abstract void visit( X x );
Тип X делаю implements YVisitor и добавляю метод
public void f( Y y )
{
y.visit( this );
}
В каждом потомке типа Y нужно теперь реализовать метод visit. Делаем это по такой схеме, для примера на классе Y1:
class Y1 extends Y
{
...
public void visit(X x)
{
x.visitY1(this);
}
}
Очень важный момент, что суффикс имени вызываемого метода должен содержать имя класса (потомка Y)! Если такого метода нет в классе X (а это означает, что еще нет соотв.visit-метода в интерфейсе), то идем в интерфейс YVisitor и добавляем метод void visitY1(Y1 y1); Таким образом, при добавлении нового потомка типа Y такая схема работы позволит отследить весь необходимый новый код.
Кроме того, компилятор будет требовать реализации методов visitYi в каждом потомке типа X. Если появится новый потомок типа X, компилятор сообщит, что в нем нужно реализовать все visitYi.
Вызвать это дело следует так: x.f(y), где x типа X, y типа Y.
Этот комментарий был удален администратором блога.
ОтветитьУдалить