努力保头发的打工人
努力保头发的打工人
发布于 2020-12-30 / 34 阅读 / 0 评论 / 0 点赞

访问者模式

1 概述

定义 封装一些作用于某种数据结构中个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

通用类图:

访问者模式类图.png

  • visitor 抽象访问者,抽象类或接口,声明可以访问那些元素

  • concretevisitor 具体访问者,访问到一个类应该干什么

  • element 抽象元素,接口或抽象类,声明接收哪一类访问者访问

  • concreteelement 具体元素

  • objectstruture 结构对象,元素生产者,容纳多个不同的类的容器,如:list、set、map等

2 优缺点

2.1 优点
  • 符合单一职责原则,具体元素负责数据的加载,访问类负责展现

  • 优秀的扩展性:由于职责分开,增加数据操作是很方便的

  • 灵活性非常高:根据不同类型调用不同的accept方法

2.2 缺点
  • 具体元素对访问者公布细节:访问者关注了其他类的内部细节,与迪米特法则建议不符

  • 具体元素变更比较困难:涉及到访问者的代码

  • 违背了依赖倒置原则:访问者依赖的是具体元素而不是抽象接口

3 使用场景

一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于去具体类的操作;需要对一个对象结构中的对象进行很多不同且不相关的操作,而你想避让这些操作“污染”这些对象的类。

4 代码示例

创建元素抽象和具体元素

/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 抽象元素
 */
public abstract class ElementAbstract {
​
    /**
     * 定义公共方法
     */
    public abstract void doSomething();
​
    /**
     * 定义那个访问者能访问
     */
    public abstract void accept(Visitor visitor);
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 具体元素1
 */
public class Element1 extends ElementAbstract{
    /**
     * 定义公共方法
     */
    @Override
    public void doSomething() {
        System.out.println("元素1做点什么...");
    }
​
    /**
     * 定义那个访问者能访问
     *
     * @param visitor
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 具体元素2
 */
public class Element2 extends ElementAbstract{
    /**
     * 定义公共方法
     */
    @Override
    public void doSomething() {
        System.out.println("元素2做了点什么...");
    }
​
    /**
     * 定义那个访问者能访问
     *
     * @param visitor
     */
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

定义访问者接口和实现类

/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 访问者接口
 */
public interface Visitor {
​
​
    void visit(Element1 element1);
​
    void visit(Element2 element2);
}
​
/**
 * @author chiangtaol
 * @date 2020-12-09
 * @describe 具体访问者
 */
public class VisitorImpl implements Visitor{
​
    @Override
    public void visit(Element1 element1) {
        element1.doSomething();
    }
​
    @Override
    public void visit(Element2 element2) {
        element2.doSomething();
    }
}

测试代码,其中list充当类图中的元素容器

@Test
void doSomething() {
    List<ElementAbstract> list = new ArrayList<>();
    ElementAbstract element1 = new Element1();
    ElementAbstract element2 = new Element2();
    list.add(element1);
    list.add(element2);
​
​
    VisitorImpl visitor = new VisitorImpl();
    for (ElementAbstract elementAbstract : list){
        elementAbstract.accept(visitor);
    }