访问者模式(Visitor Pattern)属于对象行为型模式的一种,表示一个作用于其对象结构中的各元素的操作,它可以在不改变各元素类的前提下定义作用于这些元素的新操作。
可以这么说,访问者模式算是 GOF 23 中设计模式中最复杂的一个,在实际开发中,使用不是非常广泛。访问者模式的类图如下,
我们先来通过一个具体的例子了解一下访问者模式,首先定义两个接口,一个表示被访问对象的内部元素,另外一个表示访问者对象,
public interface ElementNode {
void accept(Visitor visitor);
}
public interface Visitor {
void visitElementNodeA(ConcreteElementNodeA nodeA);
void visitElementNodeB(ConcreteElementNodeB nodeB);
}
定义两个基于上述内部元素接口的两个具体元素类,
public class ConcreteElementNodeA implements ElementNode{
public void accept(Visitor visitor) {
visitor.visitElementNodeA(this);
}
}
public class ConcreteElementNodeB implements ElementNode{
public void accept(Visitor visitor) {
}
}
定义两个基于上述访问者接口的两个具体访问者类,
public class ConcreteVisitorA implements Visitor{
public void visitElementNodeA(ConcreteElementNodeA nodeA) {
System.out.println("Node A is visited by visitor A");
}
public void visitElementNodeB(ConcreteElementNodeB nodeB) {
System.out.println("Node B is visited by visitor A");
}
}
public class ConcreteVisitorB implements Visitor{
public void visitElementNodeA(ConcreteElementNodeA nodeA) {
System.out.println("Node A is visited by visitor B");
}
public void visitElementNodeB(ConcreteElementNodeB nodeB) {
System.out.println("Node B is visited by visitor B");
}
}
测试类:
public class VisitorTest {
public static void main(String[] args) {
ConcreteElementNodeA e1 = new ConcreteElementNodeA();
ConcreteElementNodeB e2 = new ConcreteElementNodeB();
Visitor v1 = new ConcreteVisitorA();
Visitor v2 = new ConcreteVisitorB();
v1.visitElementNodeA(e1);
v1.visitElementNodeB(e2);
v2.visitElementNodeA(e1);
v2.visitElementNodeB(e2);
}
}
运行结果:
一般而言,如果对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作,或者需要对一个对象结构中的对象进行很多不同的并且不相关的操作,同时避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类吗,那么访问者模式值得一试。
从上述代码可以看出,访问者模式的优缺点还是很明显的:
优点:
符合单一职责原则; 优秀的扩展性;灵活性。缺点:
具体元素对访问者公布细节,违反了迪米特原则;具体元素变更比较困难;违反了依赖倒置原则,依赖了具体类,没有依赖抽象。