访问者模式定义
提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式结构图
访问者模式角色介绍
抽象访问者:Vistor,抽象访问者为每一个具体元素类ConcreteElement声明一个访问操作,从参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。
具体访问者:ConcreteVisitor,具体访问者实现了由抽象访问者声明的操作,每一个操作用于访问一个具体元素。
抽象元素:Element,抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。
具体元素:ConcreteElement,具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对该元素的操作。
访问者模式结构代码
抽象访问者:
public interface Visitor {
/**
* 访问具体元素A
* @param concreteElementA
*/
void visit(ConcreteElementA concreteElementA);
/**
* 访问具体元素B
* @param concreteElementB
*/
void visit(ConcreteElementB concreteElementB);
}
具体访问者:
public class ConcreteVisitor implements Visitor {
public void visit(ConcreteElementA concreteElementA) {
System.out.println(concreteElementA.getAttribute() +"-"+concreteElementA.getA());
}
public void visit(ConcreteElementB concreteElementB) {
System.out.println(concreteElementB.getAttribute() +"-"+concreteElementB.getB());
}
}
抽象元素:
public interface Element {
void accept(Visitor visitor);
}
具体元素A:
public class ConcreteElementA implements Element {
private String attribute;
private String a;
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
}
具体元素B:
public class ConcreteElementB implements Element {
private String attribute;
private String b;
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
}
客户端:
public class Client {
public static void main(String[] args) {
Visitor visitor = new ConcreteVisitor();
List<Element> elements = loadElements();
for (Element e:elements) {
e.accept(visitor);
}
}
private static List<Element> loadElements(){
ConcreteElementA concreteElementA = new ConcreteElementA();
concreteElementA.setA("A");
concreteElementA.setAttribute("公共A");
ConcreteElementB concreteElementB = new ConcreteElementB();
concreteElementB.setB("B");
concreteElementB.setAttribute("公共B");
List<Element> elements = new ArrayList<Element>();
elements.add(concreteElementA);
elements.add(concreteElementB);
return elements;
}
}
访问者模式运行机制
元素对象针对抽象访问者编程,元素的accept方法入参为抽象访问者类型;
访问者针对具体元素编程,有多少个具体元素,就需要定义多少个visit方法,其入参为具体元素类型;
访问者模式具体执行过程如下:
(1) 调用具体元素类的accept(Visitor visitor)方法,并将Visitor子类对象作为其参数;
(2) 在具体元素类accept(Visitor visitor)方法内部调用传入的Visitor对象的visit()方法,如visit(ConcreteElementA elementA),将当前具体元素类对象(this)作为参数,如visitor.visit(this);
(3) 执行Visitor对象的visit()方法,通过入参的具体元素对象,实现对元素的访问操作。
因为元素针对抽象访问者编程,所以增加具体访问者对原程序无任何影响,符合开闭原则;访问者针对具体元素编程,如果增加元素,所有的访问者都需要增加对新元素的访问处理,此时不符合开闭原则。
访问者模式解决的核心问题
数据结构和数据所具有的属性是固定不变的,但数据展示操作可能随时改变,通过访问者模式,可以轻松实现变更数据展示形式。