相关课程的多个访客

时间:2016-03-25 04:58:43

标签: java design-patterns architecture visitor visitor-pattern

我简化了一些事情来指出我的基本设计问题。

我有这样的层次结构:

BRA

其中BRBBRCRRARRBRRCpublic 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

我的解决方法是在抽象类BRRR中定义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}}

但必须有一个更优雅的解决方案来组合两个访客类别。

2 个答案:

答案 0 :(得分:1)

好吧,我想我现在已经找到了更好的东西,Selective Visitor Pattern, as described here启发了。但是,我仍然愿意接受优雅的解决方案。

定义了一个新类SelectiveVisitor,它现在是Client拥有的访问者类的唯一引用。接口R现在声明了另一种方法:

public interface R {
    /* . . . */
    public accept(SelectiveVisitor sv);
}

因此,BRRR的修改方式如下:

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方法都会被BRRR的子类之一调用。

visit的{​​{1}}方法已重载。每次调用时,都会动态选择最具体的版本,因此最适合的访问者访问SelectiveVisitor

我将这篇文章留在这里,以防万一有人在将来遇到类似的设计问题,到那时还没有提出更好的建议。

答案 1 :(得分:0)

以下是访客模式的示例。请注意,这是一个访问者,其中包含针对每种访问点的.complete()方法。

visit()