访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。
数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做"双重分派"。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。
双重分派意味着施加于节点之上的操作是基于访问者和节点本身的数据类型,而不仅仅是其中的一者。
一,结构:
抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口。
具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。
抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参量。
具体节点(Node)角色:实现了抽象元素所规定的接受操作。
结构对象(ObiectStructure)角色:有如下的一些责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)。
二,示例代码:
/**
* 抽象访问者(Visitor)角色
* @author Salmon
*
*/
public interface Visitor {
public void visitConcreteElementA(ConcreteElementA concreteElementA);
public void visitConcreteElementB(ConcreteElementB concreteElementB);
}
/**
* 具体访问者(ConcreteVisitor)角色
* @author Salmon
*
*/
public class ConcreteVisitor1 implements Visitor {
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
System.out.println("");
}
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
System.out.println("");
}
}
/**
* 具体访问者(ConcreteVisitor)角色
* @author user
*
*/
public class ConcreteVisitor2 implements Visitor {
public void visitConcreteElementA(ConcreteElementA concreteElementA) {
// Console.WriteLine( "{0} visited by {1}",
// concreteElementA, this );
}
public void visitConcreteElementB(ConcreteElementB concreteElementB) {
// Console.WriteLine( "{0} visited by {1}",
// concreteElementB, this );
}
}
/**
* 抽象节点(Node)角色
* @author Salmon
*
*/
public interface Element {
public void accept(Visitor visitor);
}
/**
* 具体节点(Node)角色
* @author Salmon
*
*/
public class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public void OperationA() {
}
}
/**
* 具体节点(Node)角色
* @author Salmon
*
*/
public class ConcreteElementB implements Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void OperationB() {
}
}
public class ObjectStructure {
private ArrayList<Element> elements = new ArrayList<Element>();
public void attach(Element element) {
elements.add(element);
}
public void detach(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element e : elements)
e.accept(visitor);
}
}
/**
* 客户端代码
* @author Salmon
*
*/
public class Client {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
o.attach(new ConcreteElementA());
o.attach(new ConcreteElementB());
ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor2 v2 = new ConcreteVisitor2();
o.accept(v1);
o.accept(v2);
}
}