一、概述
一般问题:对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
核心方案:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
设计意图:一般情况下,一个类会封装一些属性,同时会提供访问这些属性的方法。如果这个类的属性是稳定的,但是访问属性的接口却经常变动,也就是经常需要修改类代码,显然不符合“开闭原则”。在设计模式里,没有什么是不能拆的,既然数据结构稳定,数据操作经常改变,那就把数据操作封装到单独的类中好了,然后再在这些类中定义好对每种数据类型的访问方法,这就是最初的访问者模式了。
访问者模式的类图在众多设计模式里属于比较复杂的。我们分成两部分来看:
(1)数据结构端
- Element定义元素类,是所有数据类型的抽象类,需要定义accept接口,用来接受访问者。
- ObjectStructure为元素类容器
(2)数据访问端
Visitor定义访问者类,是所有访问者的抽象类,需要定义各个元素的visite接口,用于对不同元素的区别对待
二、应用实战
实际开发中用到访问者模式的地方很少,没有必要无中生有一个故事,硬套上设计模式。Java新特性——注解——其解析原理的确用到了访问者模式。编译时Annotation解析的基本原理是:在某些代码元素上(如类型,函数,字段等)添加注解,在编译时编译器会检查AbstractProcessor的子类,并且调用该类型的process函数,然后将添加了注解的所有元素都传递到process函数中,使得开发人员可以在编译期进行相应的处理, 例如根据注解生成新的java类,这也就是ButterKnife等开源库的基本原理.
- PackageElement - 包元素,包含某个包下面的信息,可以获取到包名等
- TypeElement - 类型元素,如某个字段属于某种类型
- ExecutableElement - 可执行元素,代表了函数类型的元素
- VariableElement - 变量元素
- TypeParameterElement - 类型参数元素
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { //定义注解的属性,这不是方法 String name();//必选注解 int value() default 20;//有属性就是可选属性 }
Element类如下:
public interface Element { //代码省略 //获取元素类型 ElementKind getKind(); //获取修饰符,如public 、 static 、final等 Set<Modifier> getModifiers(); //接受访问者的访问 <R, P> R accept(ElementVisitor<R, P> P p); }
Element中有一个<R, P> R accept(ElementVisitor<R, P> var1, P var2); ,这里就是利用访问者模式去访问Element中的所有元素信息。
再看Visitor类:
public interface ElementVisitor<R, P> { //访问元素 R visit(Element e, P p); //访问包元素 R visitPackage(PackageElement e, P p); //访问一个类型元素 R visitType(TypeElement e, P p); //访问一个变量类型 R visitVariable(VariableElement e, P p); //访问一个可执行元素 R visitExecutable(ExecutableElement e, P p); //访问一个参数元素 R visitTypeParameter(TypeParameterElement e, P p); //处理未知的元素类型,这是为了应对后续java语言的扩展而预留的接口 //例如后续元素类型增加,那么通过这个接口就可以处理上述没有声明的类型 R visitUnknown(Element e, P p); }
ElementVisitor中定义了很多visit方法,每个visit方法对应一种元素,这就是典型的访问者模式。一个类元素和一个函数元素是完全不一样的,它们的结构不一样,因此,编译器对它们的操作也不同,通过访问者模式正好解决数据结构与数据操作分离的问题。
三、总结
总结:访问者模式是一种行为型设计模式,在现实情况下,我们根据具体的情况来评估是否适合使用访问者模式,例如,我们的对象结构是否稳定,使用访问者模式是否优化我们的代码,而不是使得代码变得更加复杂。
用一句话来表述访问者模式:
横看成岭侧成峰
优点:使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
缺点:
- 具体元素变更时导致修改成本大
- 违反了依赖倒置原则,为了达到区别对待而依赖了具体类,没有依赖抽象
来源:https://www.cnblogs.com/not2/p/11089979.html