搬砖小弟
设计模式-访问者模式
2019-06-30 / 4 min read

定义

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. (封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。)

UML

代码实现

public abstract class Element {
     //定义业务逻辑
     public abstract void doSomething();
     //允许谁来访问
     public abstract void accept(IVisitor visitor);
}
public class ConcreteElement1 extends Element{
     //完善业务逻辑
     public void doSomething(){
             //业务处理
     }
     //允许那个访问者访问
     public void accept(IVisitor visitor){
             visitor.visit(this);
     }
}
public class ConcreteElement2 extends Element{
     //完善业务逻辑
     public void doSomething(){
             //业务处理
     }
     //允许那个访问者访问
     public void accept(IVisitor visitor){
             visitor.visit(this);
     }
}
public interface IVisitor {
     //可以访问哪些对象
     public void visit(ConcreteElement1 el1);
     public void visit(ConcreteElement2 el2);
}
public class Visitor implements IVisitor {
     //访问el1元素
     public void visit(ConcreteElement1 el1) {
             el1.doSomething();
     }
     //访问el2元素
     public void visit(ConcreteElement2 el2) {
             el2.doSomething();
     }
}
public class ObjectStruture {
     //对象生成器,这里通过一个工厂方法模式模拟
     public static Element createElement(){
             Random rand = new Random();
             if(rand.nextInt(100) > 50){
                     return new ConcreteElement1();
             }else{
                     return new ConcreteElement2();
             }
     }
}
public class Client {
     public static void main(String[] args) {
             for(int i=0;i<10;i++){
                     //获得元素对象
                     Element el = ObjectStruture.createElement();
                     //接受访问者访问
                     el.accept(new Visitor());
             }          
     }
}

访问者模式的优点

  • 符合单一职责原则
    具体元素角色也就是Employee抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个不同的职责非常明确地分离开来,各自演绎变化。
  • 优秀的扩展性
    由于职责分开,继续增加对数据的操作是非常快捷的,例如,现在要增加一份给大老板的报表,这份报表格式又有所不同,直接在Visitor中增加一个方法,传递数据后进行整理打印。
  • 灵活性非常高

访问者模式的缺点

  • 具体元素对访问者公布细节
    访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的。
  • 具体元素变更比较困难
    具体元素角色的增加、删除、修改都是比较困难的,就上面那个例子,你想想,你要是想增加一个成员变量,如年龄age,Visitor就需要修改,如果Visitor是一个还好办,多个呢?业务逻辑再复杂点呢?
    -- 违背了依赖倒置转原则
    访问者依赖的是具体元素,而不是抽象元素,这破坏了依赖倒置原则,特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较难。

访问者模式的使用场景

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。
  • 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。

JDK中的访问者模式

  • javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
  • javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor