一、访问者模式定义
1.访问者模式是一种将数据结构与数据操作分离的设计模式,是指封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。属于行为型模式。
2.访问者模式被称为最复杂的设计模式,并且使用频率不高,设计模式的作者也评价为:大多情况下,你不需要使用访问者模式,但是一旦需要使用它时,那就真的需要使用了。访问者模式的基本思想是,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个accept()方法用来接受访问者对象的访问。不同的访问者对同一元素的访问内容不同,使得相同的元素集合可以产生不同的数据结果。accept()方法可以接收不同的访问者对象,然后在内部将自己(元素)转发到接收到的访问者对象的visit()方法内。访问者内部对应类型的visit()方法就会得到回调执行,对元素进行操作。也即是通过两次动态分发(第一次是对访问者的分发accept()方法,第二次是对元素的分发visit()方法),才最终将一个具体的元素传递到一个具体的访问者。如此一来,就解耦了数据结构与操作,且数据操作不会改变元素状态
3.访问者模式的核心是解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性。可以通过扩展不同的数据操作类型(访问者)实现对相同元素集的不同的操作
4.访问者模式的适用场景:
A.数据结构稳定,作用于数据结构的操作经常变化的场景
B.需要数据结构与数据操作分离的场景
C.需要对不同数据类型(元素)进行操作,而不使用分支判断具体类型的场景
二、访问者模式示例
1.访问者模式一般包含5种角色:
A.抽象访问者(Visitor):接口或抽象类
B.具体访问者(ConcreteVisitor):实现对具体元素的操作
C.抽象元素(Element):接口或抽象类,定义了一个接受访问者访问的方法accept(),表示所有元素类型都支持被访问者访问
D.具体元素(ConcreteElement):具体元素类型,提供接受访问者的具体实现,通常的实现都为:visitor.visit(this)
E.结构对象(ObjectStructure):该类内部维护了元素集合,并提供方法接受访问者对该集合所有元素进行操作
2.代码示例
1 // 抽象访问者
2 public interface IVisitor {
3
4 void visit(ConcreteElementA element);
5
6 void visit(ConcreteElementB element);
7 }
8
9 // 具体访问者
10 public class ConcreteVisitorA implements IVisitor {
11
12 public void visit(ConcreteElementA element) {
13 String result = element.operationA();
14 System.out.println("result from " + element.getClass().getSimpleName() + ": " + result);
15 }
16
17 public void visit(ConcreteElementB element) {
18 int result = element.operationB();
19 System.out.println("result from " + element.getClass().getSimpleName() + ": " + result);
20 }
21 }
22
23 // 具体访问者
24 public class ConcreteVisitorB implements IVisitor {
25
26 public void visit(ConcreteElementA element) {
27 String result = element.operationA();
28 System.out.println("result from " + element.getClass().getSimpleName() + ": " + result);
29 }
30
31
32 public void visit(ConcreteElementB element) {
33 int result = element.operationB();
34 System.out.println("result from " + element.getClass().getSimpleName() + ": " + result);
35 }
36 }
37
38 // 抽象元素
39 public interface IElement {
40 void accept(IVisitor visitor);
41 }
42
43 // 具体元素
44 public class ConcreteElementA implements IElement {
45
46 public void accept(IVisitor visitor) {
47 visitor.visit(this);
48 }
49
50 public String operationA() {
51 return this.getClass().getSimpleName();
52 }
53
54 }
55
56 // 具体元素
57 public class ConcreteElementB implements IElement {
58
59 public void accept(IVisitor visitor) {
60 visitor.visit(this);
61 }
62
63 public int operationB() {
64 return new Random().nextInt(100);
65 }
66 }
67
68 // 结构对象
69 public class ObjectStructure {
70 private List<IElement> list = new ArrayList<IElement>();
71
72 {
73 this.list.add(new ConcreteElementA());
74 this.list.add(new ConcreteElementB());
75 }
76
77 public void accept(IVisitor visitor) {
78 for (IElement element : this.list) {
79 element.accept(visitor);
80 }
81 }
82 }
83
84 public class Test {
85
86 public static void main(String[] args) {
87 ObjectStructure collection = new ObjectStructure();
88 System.out.println("ConcreteVisitorA handle elements:");
89 IVisitor visitorA = new ConcreteVisitorA();
90 collection.accept(visitorA);
91 System.out.println("------------------------------------");
92 System.out.println("ConcreteVisitorB handle elements:");
93 IVisitor visitorB = new ConcreteVisitorB();
94 collection.accept(visitorB);
95 }
96
97 }
3.访问者模式的优缺点
A.优点
a.解耦了数据结构和数据操作,使得操作集合可以独立变化
b.扩展性好:可以通过扩展访问者角色,实现对数据集的不同操作
c.元素具体类型并非单一,访问者均可操作
d.各角色职责分离,符合单一职责原则
B.缺点