在Wikipedia
sample和GoF书中,访问者模式的使用是通过在某个接受者上调用accept方法来启动的.但为什么会这样呢?为什么我们不能开始使用所需的acceptor作为参数调用visit方法?我们仍然可以使访问者行为依赖于两种类型 – 访问者和接受者(双重调度) – 并且我们可以消除冗余呼叫(在我看来).
这是用于说明这一点的示例代码:
public interface Visitor { void visit(AcceptorA acceptor); void visit(AcceptorB acceptor); } // // Visitor which sings // class SingingVisitor implements Visitor { public void visit(AcceptorA acceptor) { System.out.println("sing A"); } public void visit(AcceptorB acceptor) { System.out.println("sing B"); } } // // Visitor which talks // class TalkingVisitor implements Visitor { public void visit(AcceptorA acceptor) { System.out.println("talk A"); } public void visit(AcceptorB acceptor) { System.out.println("talk B"); } } // // Acceptor subclasses // class AcceptorA implements BaseAcceptor { } class AcceptorB implements BaseAcceptor { } // // Launcher class // class VisitorMain { public static void main(String[] args) { Visitor v = new TalkingVisitor(); AcceptorA a = new AcceptorA(); AcceptorB b = new AcceptorB(); v.visit(a); v.visit(b); v = new SingingVisitor(); v.visit(a); v.visit(b); } }
解决方法
考虑:
class House implements HouseAcceptor { HouseAcceptor kitchen; HouseAcceptor livingRoom; void accept(HouseVisitor visitor) { visitor.visit(this); kitchen.accept(visitor); livingRoom.accept(visitor); } } class Kitchen implements HouseAcceptor { void accept(HouseVisitor visitor) { visitor.visit(this); } } class LivingRoom implements HouseAcceptor { void accept(HouseVisitor visitor) { visitor.visit(this); } } class SpeakingHouseVisitor implements HouseVisitor { void visit(HouseAcceptor acceptor) { System.out.println("Inside a HouseAcceptor"); } void visit(House acceptor) { System.out.println("Inside a House"); } void visit(Kitchen acceptor) { System.out.println("Inside a Kitchen"); } void visit(LivingRoom acceptor) { System.out.println("Inside a LivingRoom"); } } ... HouseAcceptor acceptor = new House(); HouseVisitor visitor = new SpeakingHouseVisitor(); ... // Doing it your way visitor.visit(acceptor); // Output: Inside a HouseAcceptor // Doing it the right way acceptor.accept(visitor); // Output: // Inside a House // Inside a Kitchen // Inside a LivingRoom
请注意,如果按照自己的方式执行,接受器的运行时类型将没有区别:将使用静态类型.通过执行双重调度,您可以确保使用两种运行时类型.