1 概述
定义 封装一些作用于某种数据结构中个元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
通用类图:
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);
}