模式定义
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
模式示例
下面以电脑启动时对各个组成部分的访问为例来说明访问者模式。主要以下几个步骤
- 定义元素接口,被访问者需要实现这个接口;
- 定义访问者接口,访问者需要实现该接口;
- 具体实现被访问者类和访问者类
- 编写客户端验证
定义元素接口
1 | /** |
定义访问者接口
1 | /** |
这里给访问者传递的都是具体的类,如果被访问者新增元素,需要增加相应的方法,同时访问者类的实现者需要实现该方法,违反了迪米特原则。
具体实现被访问者和访问者
1 | /** |
这是元素对象,本身可被访问,同时其组成部分也可被访问。
1 | /** |
1 | /** |
1 | /** |
定义访问者,先看整体访问者
1 | /** |
输入设备访问者
1 | /** |
用来验证的客户端
1 | public class VisitorPatternDemo { |
输出结果:
1 | == Show all computer part: == |
可以看到,访问者还是可能会有一些方法的冗余的,比如UserInputVisitor
,不需要访问Monitor
和Computer
但却不得不实现访问者接口定义的方法(空实现)
模式总结
使用访问者模式时,通常这个类(元素类)的结构(数据结构)比较固定,主要解决稳定的数据结构和易变的操作耦合问题。
优缺点
- 优点
- 符合单一职责原则。
- 优秀的扩展性。
- 灵活性。
- 缺点
- 具体元素对访问者公布细节,违反了迪米特原则(一个对象应该尽可能的减少对其他元素的了解)。
- 具体元素变更比较困难。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用场景
对固定多部分组成对象元素进行不同的操作时可以用到该模式。如电脑的结构固定,我可以定义一个访问者只访问输入设备,也可以定义一个访问者访问显示设备。
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类。
注意事项
- 如果元素经常变动,结构不固定,就不适合使用访问者模式了,因为该模式增加新元素比较困难;
- 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
- 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者,已让访问者访问。
- 在被访问的类里面加一个对外提供接待访问者的接口。