访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
UML图:
package com.thpin.repository.designpattern;
import java.util.ArrayList;
import java.util.List;
public class VisitorDemo {
public static void main(String[] args) {
ObjectStructure os = new ObjectStructure();
Element elementA = new ConcreteElementA();
Element elementB = new ConcreteElementB();
os.attach(elementA);
os.attach(elementB);
Visitor visitor1 = new ConcreteVistor1();
Visitor visitor2 = new ConcreteVistor2();
os.accept(visitor1);
os.accept(visitor2);
}
}
/*
* 访问者抽象类
*/
abstract class Visitor {
public abstract void visitConcreteElementA(ConcreteElementA elementA);
public abstract void visitConcreteElementB(ConcreteElementB elementB);
}
/*
* 访问者1
*/
class ConcreteVistor1 extends Visitor {
public void visitConcreteElementA(ConcreteElementA elementA) {
System.out.print("ConcreteVistor1访问了");
elementA.oprationA();
}
public void visitConcreteElementB(ConcreteElementB elementB) {
System.out.print("ConcreteVistor1访问了");
elementB.oprationB();
}
}
/*
* 访问者2
*/
class ConcreteVistor2 extends Visitor {
public void visitConcreteElementA(ConcreteElementA elementA) {
System.out.println(this.getClass().getSimpleName() + "访问了" + elementA.getClass().getSimpleName());
}
public void visitConcreteElementB(ConcreteElementB elementB) {
System.out.println(this.getClass().getSimpleName() + "访问了" + elementB.getClass().getSimpleName());
}
}
/*
* 被访问者抽象类
*/
abstract class Element {
public abstract void accept(Visitor visitor);
}
/*
* 被访问者A
*/
class ConcreteElementA extends Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
public void oprationA() {
System.out.println("ConcreteElementA.oprationA()");
}
}
/*
* 被访问者A
*/
class ConcreteElementB extends Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
public void oprationB() {
System.out.println("ConcreteElementB.oprationB()");
}
}
/*
* 对象结构类
*/
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void attach(Element element) {
elements.add(element);
}
public void detach(Element element) {
elements.remove(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
结果:
ConcreteVistor1访问了ConcreteElementA.oprationA()
ConcreteVistor1访问了ConcreteElementB.oprationB()
ConcreteVistor2访问了ConcreteElementA
ConcreteVistor2访问了ConcreteElementB
访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。访问者模式的主要目的是要把处理从数据结构分离出来,很多系统可以按照酸和和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易,增加新的操作意味着增加一个新的访问者它。访问者模式将有关的行为集中到一个访问者对象中。
但它也有缺点就是使增加新的数据结构变得困难了,也就是Element的子类的增加会给访问者带来很大的改动,加一个子类所有的访问者都要多加一个访问这个子类的方法,违反了开闭原则。所以说访问者模式适用于数据结构稳定的系统,类似于人类在性别层面分为男人和女人,不能再改变了,这样的数据结构就可以使用访问者模式。除非你确定数据结构是不变的情况下再考虑使用访问者模式。
这样说吧,最开始系统中的数据结构Element只有两个子类ElementA和ElementB,在一段时间内,围绕着他们产生了很多Visitor子类Visitor1...100 ,正当这时你欣喜若狂于只扩展访问者太利于维护了,突然需求变更多出来一个ElementC,我靠!难道你要在这100个访问者里都加一个访问ElementC的方法?这就是噩梦,所以一定要考察好了你想要设计的数据结构不会变化,但是处理数据的行为时常变化的时候再考虑使用观察者模式。