Я упрощаю вещи, чтобы указать на мою основную проблему с дизайном.Несколько посетителей по смежным классам
У меня есть иерархия, как это:
R <-- interface
/ \
/ \
/ \
BR RR <-- abstract classes
/| \ /| \
/| \ /| \
BRA BRB BRC RRA RRB RRC <-- classes
где BRA
, BRB
, BRC
, RRA
, RRB
и RRC
классы, которые необходимо посетить.
У меня также есть два класса посетителей, которые не имеют общего класса предков (на данный момент). Таким образом, в конце концов, код структурирован следующим образом:
public interface R {
/* . . . */
}
public abstract class BR implements R {
/* . . . */
public abstract void accept(VisitorBR vbr);
}
public abstract class RR implements R {
/* . . . */
public abstract void accept(VisitorRR vrr);
}
public class BRA extends BR {
/* . . . */
public void accept(VisitorBR vbr) { vbr.visit(this); }
}
public class BRB extends BR {
/* . . . */
public void accept(VisitorBR vbr) { vbr.visit(this); }
}
public class BRC extends BR {
/* . . . */
public void accept(VisitorBR vbr) { vbr.visit(this); }
}
public class RRA extends RR {
/* . . . */
public void accept(VisitorRR vrr) { vrr.visit(this); }
}
public class RRB extends RR {
/* . . . */
public void accept(VisitorRR vrr) { vrr.visit(this); }
}
public class RRC extends RR {
/* . . . */
public void accept(VisitorRR vrr) { vrr.visit(this); }
}
и
public class VisitorBR {
/* . . . */
public void visit(BRA r) { /* . . . */ }
public void visit(BRB r) { /* . . . */ }
public void visit(BRC r) { /* . . . */ }
}
public class VisitorRR {
/* . . . */
public void visit(RRA r) { /* . . . */ }
public void visit(RRB r) { /* . . . */ }
public void visit(RRC r) { /* . . . */ }
}
Класс клиент имеет BlockingQueue<R>
и одну ссылку на объект каждого класса посетителей, и должен обрабатывать все элементы очереди, используя наиболее подходящего посетителя. Нам нравится это:
public class Client implements Runnable {
private VisitorBR vbr;
private VisitorRR vrr;
private BlockingQueue<R> q;
/* . . . */
@Override
void run() {
for (;;) {
R r = q.take();
/*** Somehow handle r with the most suitable visitor, ***/
/*** based on whether it's descendant of BR or RR. ***/
}
}
}
Что будет самым элегантным решением для этого? Кстати, в любом случае, посетители не должны быть вложенными классами, и я стараюсь избегать использования instanceof
.
Мой обходной путь заключается в определении public static final
перечислений полей в абстрактных классах BR
и RR
различать их и использовать if
блок, что-то вроде этого:
@Override
void run() {
for (;;) {
R r = q.take();
if (r.getType() == BR)
((BR) r).accept(vbr);
else // if (r.getType() == RR)
((RR) r).accept(vrr)
}
}
Но там должно быть более элегантное решение объединить два класса посетителей, чем это.
Я думаю, что вы ищете двойную отправку. См. Https://sourcemaking.com/design_patterns/visitor/java/2. –
@AdiLevin Я знаю об этом источнике, я просто не мог приспособить его к моему делу. – chrk