访问者模式
目的
为一个对象结构(比如组合结构)增加新能力。
类图
角色
- Visitor: 访问者。为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor: 具体访问者。存储遍历过程中的累计结果
- ObjectStructure: 对象结构。可以是组合结构,或者是一个集合。
- Element:抽象元素。抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。
- ConcreteElement:具体元素。具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
实现
访问者
interface Visitor {
public void visit(ConcreteElement1 el1);
public void visit(ConcreteElement2 el2);
}
具体访问者
class ConcreteVisitor1 implements Visitor {
@Override
public void visit(ConcreteElement1 el1) {
el1.doSomething();
}
@Override
public void visit(ConcreteElement2 el2) {
el2.doSomething();
}
}
class ConcreteVisitor2 implements Visitor {
@Override
public void visit(ConcreteElement1 el1) {
el1.doSomething();
}
@Override
public void visit(ConcreteElement2 el2) {
el2.doSomething();
}
}
抽象元素
abstract class Element {
public abstract void accept(IVisitor visitor);
public abstract void doSomething();
}
具体元素
class ConcreteElement1 extends Element {
public void doSomething(){
...
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class ConcreteElement2 extends Element {
public void doSomething(){
...
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
对象结构
public class ObjectStruture {
private List<Element> list = Lists.newArrayList();
public void addElement(Element element){
list.add(element);
}
public void accept(ElementVisitor visitor) {
for (Element elem : list) {
elem.accept(visitor);
}
}
}
调用类
public class Client {
public static void main(String[] args){
ObjectStruture structure = new ObjectStruture();
structure.addElement(new ConcreteElement1());
structure.addElement(new ConcreteElement2());
structure.accept(new ConcreteVisitor1());
structure.accept(new ConcreteVisitor2());
}
}
优缺点
优点
- 符合单一职责原则。
- 优秀的扩展性。
- 灵活性。
缺点
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
JDK 中的使用
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor