表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
使用访问者模式时,我们可以将每个类中的相关操作包装在一个独立的对象中,并在使用时将对象传递给当前访问的元素,当一个元素“接受”该访问者时,该元素向访问者发送一个包含自身类信息的请求,该请求同时也将该元素本身作为一个参数,然后访问者将为该元素执行该操作。一般情况下,Visitor模式需要定义两个类层次:一个对应于接受操作的元素,另一个应用于定义对元素的操作的访问者。当需要增加新的操作时,只需要添加新的Visitor子类即可。
Visitor模式适用于,一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,或者需要对一个对象结构中的对象进行很多不同的并且不相关的操作。如果定义对象结构的类很少改变,但经常需要在此结构上定义新的操作的情况这就适用于Visitor模式,而对象结构经常改变时,每次增加Visit操作都会要改变整个Visitor的类结构,所以此时不适用于Visitor模式。
使用访问者模式使得易于增加新的操作、集中相关操作,而分离无关操作,但是这会使得增加元素子类时需要添加新的Visitor方法,而需要修改整个类层次。
public interface Element {
public void accept(Visitor visitor);
}
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.VisitElementA(this);
}
public void operationA() {
System.out.println("Do operationA!");
}
}
public class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.VisitElementB(this);
}
public void operationB() {
System.out.println("Do operationB!");
}
}
public class Visitor {
public void VisitElementA(ConcreteElementA element) {
throw new RuntimeException("Not support!");
}
public void VisitElementB(ConcreteElementB element) {
throw new RuntimeException("Not support!");
}
public void VisitObjectStructure(ObjectStructure element) {
throw new RuntimeException("Not support!");
}
}
public class ConcreteVisitor1 extends Visitor {
public void VisitElementA(ConcreteElementA element) {
System.out.println("Using ConcreteVisitor1 visit ConcreteElementA");
}
public void VisitElementB(ConcreteElementB element) {
System.out.println("Using ConcreteVisitor1 visit ConcreteElementB");
}
}
public class ConcreteVisitor2 extends Visitor {
public void VisitElementA(ConcreteElementA element) {
System.out.println("Using ConcreteVisitor2 visit ConcreteElementA");
element.operationA();
}
public void VisitElementB(ConcreteElementB element) {
System.out.println("Using ConcreteVisitor2 visit ConcreteElementB");
element.operationB();
}
}
public class ObjectStructure implements Element {
private List<Element> children = null;
public ObjectStructure() {
children = new ArrayList<>();
}
public void addElement(Element e) {
children.add(e);
}
public void removeElement(Element e) {
children.remove(e);
}
public void removeElement(int index) {
children.remove(index);
}
@Override
public void accept(Visitor visitor) {
for (Element elem : children) {
elem.accept(visitor);
}
visitor.VisitObjectStructure(this);
}
}
public class ObjectStructureVisitor extends Visitor {
public void VisitElementA(ConcreteElementA element) {
element.operationA();
}
public void VisitElementB(ConcreteElementB element) {
element.operationB();
}
public void VisitObjectStructure(ObjectStructure element) {
System.out.println("Using ObjectStructureVisitor visit ObjectStructure");
}
}
public class Client {
@Test
public void test(){
ConcreteElementA elemA = new ConcreteElementA();
ConcreteElementB elemB = new ConcreteElementB();
//test1
Visitor v1 = new ConcreteVisitor1();
elemA.accept(v1);
elemB.accept(v1);
//test2
Visitor v2 = new ConcreteVisitor2();
elemA.accept(v2);
elemB.accept(v2);
//test3
Visitor visitor = new ObjectStructureVisitor();
ObjectStructure struct = new ObjectStructure();
struct.addElement(elemA);
struct.addElement(elemB);
struct.accept(visitor);
//test4
elemA.accept(visitor);
elemB.accept(visitor);
}
}
以上代码中定义了Element类以及Visitor类层次结构,每个Element类都可以accept一个Visitor,Visitor拥有接受各种类型的Element的方法,在这些方法里Visitor可以定制各种访问方式,从而可以将多种访问方式封装在Visitor中。ObjectStructure是一种多对象的组合,它内部维护了一个列表,这就需要一个可以访问这个列表中所有Element类型的Visitor。
从上面来看,Visitor模式和Iterator模式很相似,但是迭代器模式的主要目标是遍历整个结构,这些结构具有相同的类型,而Visitor主要针对的是异构的对象结构,这些对象属于不同的类型。