设计模式-访问者模式
灿若繁星先生 Lv6

访问者模式(Visitor Parttern): 表示一个作用于某个对象结构中的各个元素的操作. 访问者模式让用户可以在不改变各元素的类的前提下定义作用于这些元素的新操作.

设计模式-概述

结构

访问者模式包含了5个角色, 分别为:

  1. 抽象访问者(Vistor): 对某个对象结构中的每个具体元素声明了一个访问操作, 访问者需要实现这些操作方法, 定义对这些元素的具体访问操作.
  2. 具体访问者(ConcreteVistor): 实现了操作方法, 每个操作对应了对象结构中的一种类型的元素.
  3. 抽象元素(Element): 声明了一个accept()方法, 用于接受访问者的访问操作.
  4. 具体元素(ConcreteElement): 实现了一个accept()方法, 在方法中调用访问者的访问方法用来完成对一个元素的操作.
  5. 对象结构(ObjectStructure): 对象结构是一个元素的集合, 用于存放元素对象, 并提供了遍历其内部元素的方法.

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@startuml visitor-1
!include common.cuml

Class(Vistor,"抽象访问者") << abstract >> {
+ visitConcreteElementA(ConcreteElementA elementA)
+ visitConcreteElementB(ConcreteElementB elementB)
}

Class(ConcreteVistorA,"具体访问者A") {
+ visitConcreteElementA(ConcreteElementA elementA)
+ visitConcreteElementB(ConcreteElementB elementB)
}

Class(ConcreteVistorB,"具体访问者B") {
+ visitConcreteElementA(ConcreteElementA elementA)
+ visitConcreteElementB(ConcreteElementB elementB)
}

Interface(Element,"抽象元素") {
+ accept(Vistor vistor) : void
}

Class(ConcreteElementA,"具体元素A") {
+ accept(Vistor vistor) : void
+ operationA() : void
}

Class(ConcreteElementB,"具体元素B") {
+ accept(Vistor vistor) : void
+ operationB() : void
}

Class(ObjectStructure,"对象结构") {
}

Class(Client,"客户端") {
}

note as NA
public void accept(Vistor vistor) {
vistor.visitConcreteElementA(this)
}
end note

note as NB
public void accept(Vistor vistor) {
vistor.visitConcreteElementB(this)
}
end note

NA -- ConcreteElementA
NB -- ConcreteElementB

Vistor <|-- ConcreteVistorA
Vistor <|-- ConcreteVistorB
Vistor <|.. Client
Client ..> ObjectStructure
ObjectStructure --> Element
Element <|.. ConcreteElementA
Element <|.. ConcreteElementB

@enduml

代码实现

  1. 创建了一个对象结构, 对象结构内包含了一些元素, 使用list存储
  2. 元素可以动态的添加或者删除.
  3. 可以定义某些访问者, 这些访问者会访问元素的特定方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class Main {
public static void main(String[] args) {
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(new ConcreteElementA());
objectStructure.addElement(new ConcreteElementB());
System.out.println("使用ConcreteVisitorA访问这个对象结构");
objectStructure.accept(new ConcreteVisitorA());
System.out.println("===============");
System.out.println("使用ConcreteVisitorB访问这个对象结构");
objectStructure.accept(new ConcreteVisitorB());
}
}

abstract class Visitor {
abstract void visit(ConcreteElementA elementA);

abstract void visit(ConcreteElementB elementB);
}

class ConcreteVisitorA extends Visitor {

@Override
void visit(ConcreteElementA elementA) {
System.out.println("ConcreteVisitorA.visit");
}

@Override
void visit(ConcreteElementB elementB) {
System.out.println("ConcreteVisitorA.visit");
}
}

class ConcreteVisitorB extends Visitor {

@Override
void visit(ConcreteElementA elementA) {
System.out.println("ConcreteVisitorB.visit");
}

@Override
void visit(ConcreteElementB elementB) {
System.out.println("ConcreteVisitorB.visit");
}
}

interface Element {
void accept(Visitor visitor);
}

class ConcreteElementA implements Element {

@Override
public void accept(Visitor visitor) {
System.out.println("ConcreteElementA.accept");
visitor.visit(this);
}

public void operationA() {

}
}

class ConcreteElementB implements Element {

@Override
public void accept(Visitor visitor) {
System.out.println("ConcreteElementB.accept");
visitor.visit(this);
}

public void operationB() {

}
}

class ObjectStructure {
private List<Element> list = new ArrayList<>();

public void accept(Visitor visitor) {
Iterator i = list.iterator();
while (i.hasNext()) {
Element next = (Element) i.next();
next.accept(visitor);
}
}

public void addElement(Element element) {
list.add(element);
}

public void removeElement(Element element) {
list.remove(element);
}
}

得到结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13

使用ConcreteVisitorA访问这个对象结构
ConcreteElementA.accept
ConcreteVisitorA.visit
ConcreteElementB.accept
ConcreteVisitorA.visit
===============
使用ConcreteVisitorB访问这个对象结构
ConcreteElementA.accept
ConcreteVisitorB.visit
ConcreteElementB.accept
ConcreteVisitorB.visit

使用场景

  1. 有一个对象结构包含多个类型的对象, 希望这些对象实施一些依赖于具体类型的操作. 在访问者中对每一种具体的类型都有一种访问操作, 不同类型的对象可以有不同的访问操作.
  2. 访问者模式将对象本身和对象的访问操作隔离, 当对同一个对象有不同的访问操作时, 可以避免让这些访问操作影响这个对象的类, 也不希望在新增访问操作时, 会影响原有的访问操作.
  3. 对象结构中的元素尽可能的少改变, 因为一旦改变, 如果有多个访问者, 每个访问者都需要对新元素进行支持(或者有默认的处理方式)

具体应用

  1. 动态代理cglib中用到了ASM, 这是一种对Java字节码文件进行访问或者修改的工具, 使用了访问者模式.
    image
  2. PropertySourcesPlaceholderConfigurer 允许我们用 Properties 文件中的属性来定义应用上下文,PropertySourcesPlaceholderConfigurer需要对配置进行表达式替换,这里就用到了BeanDefinitionVisitor. 访问的抽象元素为 BeanDefinition.对 Bean 的定义信息,比如属性值,构造方法参数或者更具体的实现.