分派
分派是指运行环境按照对象的实际类型为其绑定对应方法体的过程。在学习访问者模式之前我们需要了解双分派。
双分派:在选择一个方法时,不仅仅要根据消息接收者的运行时型别,还要根据参数的运行时类别
例子:
public class Father {
public void accept(Execute execute){
execute.method(this);
}
}
public class Son extends Father{
@Override
public void accept(Execute execute){
execute.method(this);
}
}
public class Execute {
public void method(Father father){
System.out.println("Father>>>>>");
}
public void method(Son son){
System.out.println("Son>>>>>");
}
}
public class Test {
public static void main(String[] args) {
Father father = new Father();
Father son = new Son();
Execute execute = new Execute();
father.accept(execute);
son.accept(execute);
//Father>>>>>
//Son>>>>>
}
}
总结:先动态绑定找到对应的accept方法,然后将this参数传入method方法中静态绑定。
访问者模式
访问者模式:封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。
访问者基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口。
访问者模式UML类图
-
Visitor
抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。 -
ConcreteVisitor
具体访问者:它影响访问者访问到一个类后该怎么干,要做什么事情。 -
Element
抽象元素:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。 -
ConcreteElement
具体元素:实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。 -
ObjectStruture
结构对象:元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。处理element角色的集合。
访问者模式简单实现
Action:
public interface Action {
void getManResult(Man man);
void getWomanResult(Woman woman);
}
public class Success implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人觉得可以");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人觉得可以");
}
}
public class Fail implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人觉得不可以");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人觉得不可以");
}
}
Person:
public abstract class Person {
public abstract void accept(Action action);
}
public class Man extends Person {
@Override
public void accept(Action action) {
action.getManResult(this);
}
}
public class Woman extends Person {
@Override
public void accept(Action action) {
action.getWomanResult(this);
}
}
ObjectStructure:
public class ObjectStructure {
private List<Person> peoples = new LinkedList<>();
public void attach( Person p){
peoples.add(p);
}
public void display(Action action){
for (Person p:peoples){
p.accept(action);
}
}
}
测试:
public class Test {
public static void main(String[] args) {
Success success = new Success();
Man man = new Man();
Woman woman = new Woman();
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.attach(man);
objectStructure.attach(woman);
objectStructure.display(success);
// 男人觉得可以
//女人觉得可以
}
}
总结
访问者模式符合单一职业原则,让程序具有优秀的扩展性。但违背了依赖倒转,访问者依赖的是具体元素,而不是抽象元素。