访问者模式

定义

封装作用于某数据结构(如List/Set/Map等)中的各元素的操作;
可以在不改变各元素的类的前提下,定义作用于这些元素的操作;
行为型

适用场景

  • 一个数据结构(如List/Set/Map等)包含很多类型对象
  • 数据结构与数据操作分离

优点和缺点

优点

  • 增加新的操作很容易,即增加一个新的访问者

缺点

  • 增加新的数据结构困难
  • 具体元素变更比较麻烦

结构

  • 抽象访问者角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作visit(),该操作中的参数类型标识了被访问的具体元素;
  • 具体访问者角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么;
  • 抽象元素角色:声明一个包含接受操作accept()的接口,被接受的访问者对象作为accept()方法的参数;
  • 具体元素角色:实现抽象元素角色提供的accept()操作,其方法通常都是visitor.visit(this),另外具体元素中可能还包含本身业务逻辑的相关操作。
  • 对象结构角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的多有元素的方法,通常由List/Set/Map等聚合类实现。

代码实现

假设一个场景,双十一购物,有几个小伙伴买了商品,有的想给差评,有的想给好评
抽象访问者角色
想要做出的评论的抽象,比如好评、差评

1
2
3
4
public interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}

具体访问者角色
具体的评论,比如好评差评

1
2
3
4
5
6
7
8
public class ConcreteVisitorA implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("具体访问者A访问-->" + element.operationA());
}
public void visit(ConcreteElementB element) {
System.out.println("具体访问者A访问-->" + element.operationB());
}
}

具体访问者

1
2
3
4
5
6
7
8
public class ConcreteVisitorB implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("具体访问者B访问-->" + element.operationA());
}
public void visit(ConcreteElementB element) {
System.out.println("具体访问者B访问-->" + element.operationB());
}
}

抽象元素角色
用户的抽象,里面有一个评论的方法

1
2
3
public interface Element {
void accept(Visitor visitor);
}

具体元素
用户实现具体的评论,并记录有用户的名称

1
2
3
4
5
6
7
8
public class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA() {
return "具体元素A的操作。";
}
}

具体元素

1
2
3
4
5
6
7
8
public class ConcreteElementB implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB() {
return "具体元素B的操作。";
}
}

对象结构角色
记录有所有的购买用户,只有这些用户可以进行评价

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ObjectStructure {
private List<Element> list = new ArrayList<>();
public void accept(Visitor visitor) {
Iterator<Element> i = list.iterator();
while (i.hasNext()) {
((Element) i.next()).accept(visitor);
}
}
public void add(Element element) {
list.add(element);
}
public void remove(Element element) {
list.remove(element);
}
}

测试:

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main(String[] args) {
ObjectStructure os = new ObjectStructure();
os.add(new ConcreteElementA());
os.add(new ConcreteElementB());
Visitor visitor = new ConcreteVisitorA();
os.accept(visitor);
System.out.println("------------------------");
visitor = new ConcreteVisitorB();
os.accept(visitor);
}
}

结果:

1
2
3
4
5
具体访问者A访问-->具体元素A的操作。
具体访问者A访问-->具体元素B的操作。
------------------------
具体访问者B访问-->具体元素A的操作。
具体访问者B访问-->具体元素B的操作。

UML类图