我简化了一些事情来指出我的基本设计问题。
我有这样的层次结构:
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)
}
}
块,如下所示:
{{1}}
但必须有一个更优雅的解决方案来组合两个访客类别。
答案 0 :(得分:1)
好吧,我想我现在已经找到了更好的东西,Selective Visitor Pattern, as described here启发了。但是,我仍然愿意接受优雅的解决方案。
定义了一个新类SelectiveVisitor
,它现在是Client
拥有的访问者类的唯一引用。接口R
现在声明了另一种方法:
public interface R {
/* . . . */
public accept(SelectiveVisitor sv);
}
因此,BR
和RR
的修改方式如下:
public abstract class BR implements R {
/* . . . */
public void accept(SelectiveVisitor sv) {
sv.visit(this);
}
public abstract void accept(VisitorBR vbr);
}
public abstract class RR implements R {
/* . . . */
public void accept(SelectiveVisitor sv) {
sv.visit(this);
}
public abstract void accept(VisitorRR vrr);
}
新类的定义如下:
public class SelectiveVisitor {
private VisitorBR vbr;
private VisitorRR vrr;
public SelectiveVisitor(VisitorBR vbr, VisitorRR vrr) {
this.vbr = vbr;
this.vrr = vrr;
}
public void visit(R r) {
// this method should never be called in practice
// it's here only to satisfy the selective visitor pattern
return;
}
public void visit(BR r) {
r.accept(this.vbr);
}
public void visit(RR r) {
r.accept(this.vrr);
}
}
Client
现在更改为:
public class Client implements Runnable {
private SelectiveVisitor sv;
private BlockingQueue<R> q;
/* . . . */
@Override
void run() {
for (;;) {
R r = q.take();
r.accept(sv);
}
}
}
每次调用r.accept(selectiveVisitor)
时,visit
类的SelectiveVisitor
方法都会被BR
和RR
的子类之一调用。
类visit
的{{1}}方法已重载。每次调用时,都会动态选择最具体的版本,因此最适合的访问者访问SelectiveVisitor
。
我将这篇文章留在这里,以防万一有人在将来遇到类似的设计问题,到那时还没有提出更好的建议。
答案 1 :(得分:0)
以下是访客模式的示例。请注意,这是一个访问者,其中包含针对每种访问点的.complete()
方法。
visit()