一,访问者模式
访问者模式:
- 在被访问的类里面加一个对外提供接待访问者的接口;
- 封装一些作用于某种数据结构的各元素的操作,可以在不改变数据结构的前提下,定义作用于这些元素的新的操作;
- 将数据结构和数据操作分离,解决数据结构与数据操作的耦合性问题;
二,原理类图
意图: 封装一些作用于某种数据结构的各元素的操作,可以在不改变数据结构的前提下,定义作用于这些元素的新的操作
适用性:
当需要对一个对象结构中的对象进行很多不同操作(这些操作可能没有关联),同时需要避免这些操作“污染”这些对象的类,可以考虑访问者模式;
三,实例
双分派:
首先,将Visitor作为参数传给Element(第一次分派);
然后在将Element自己传给Visitor的方法中去执行(第二次分派);
Visitor接口: 抽象访问者,为ConcreteElement中的每个类声明一个visit操作
package com.neei.visitor;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/14 20:24
* @Description: 游学网
* @throws:
*/
public interface Action {
/**
* 男性评分
*
* @param man
*/
void getManResult(Man man);
/**
* 女性评分
*
* @param woMan
*/
void getWoManResult(WoMan woMan);
}
ConcreteVisitor: 具体的访问者,实现每个Visitor声明的操作,是每个操作的实现部分。
package com.neei.visitor;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/14 20:30
* @Description: 游学网
* @throws:
*/
public class Success implements Action {
@Override
public void getManResult(Man man) {
System.out.println(man.getName() + ":机智过人");
}
@Override
public void getWoManResult(WoMan woMan) {
System.out.println(woMan.getName() + ":机智过人");
}
}
public class Fail implements Action {
@Override
public void getManResult(Man man) {
System.out.println(man.getName() + ":技不如人");
}
@Override
public void getWoManResult(WoMan woMan) {
System.out.println(woMan.getName() + ":技不如人");
}
}
public class Equal implements Action {
@Override
public void getManResult(Man man) {
System.out.println(man.getName() + ":不相上下");
}
@Override
public void getWoManResult(WoMan woMan) {
System.out.println(woMan.getName() + ":不相上下");
}
}
ObjectStructure: 能够枚举元素,提供一个高层的接口,允许访问者访问元素;
package com.neei.visitor;
import java.lang.invoke.VolatileCallSite;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/14 20:40
* @Description: 游学网
* @throws:
*/
public class ObjectStructure {
private List<Person> list = new LinkedList<>();
public void add(Person person) {
list.add(person);
}
public void deleted(Person person) {
list.remove(person);
}
public void display(Action action) {
for (Person person : list) {
person.accept(action);
}
}
}
Element接口: 定义accept方法,接收一个访问者对象;
package com.neei.visitor;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/14 20:24
* @Description: 游学网
* @throws:
*/
public abstract class Person {
/**
* 提供访问方法
*
* @param action
*/
abstract void accept(Action action);
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(String name) {
this.name = name;
}
}
ConcreteElement: 具体元素,实现accept方法;
package com.neei.visitor;
/**
* @param
* @Author: AaNeei
* @Date: 2019/10/14 20:29
* @Description: 游学网
* @throws:
*/
public class WoMan extends Person {
public WoMan(String name) {
super(name);
}
/**
* 双分派
* @param action
*/
@Override
void accept(Action action) {
action.getWoManResult(this);
}
}
public class Man extends Person {
public Man(String name) {
super(name);
}
/**
* 双分派
* @param action
*/
@Override
void accept(Action action) {
action.getManResult(this);
}
}
四,源码分析
JDK源码中使用的访问者模式,如java.nio.file.FileVisitor;