背景
在 Visitor 模式中,数据结构与处理被分离开来。我们编写一个表示访问者的类来访问数据结构中的元素,并把对各元素的处理交给访问者类。这样,当需要增加新的处理时,我们只需要写新的访问者,然后让数据结构可以接受访问者的访问即可;
登场角色
Visitor 访问者
Visitor 角色负责对 数据结构中每个具体的元素声明一个用于访问XXXX的visit(xxxx)方法。visit(xxxx)是用于处理XXXX方法,负责实现的是ConcreteVisitor角色;
ConcreteVisitor 具体访问者
ConcreteVisitor 角色负责实现 Visitor 角色所定义的接口(API) 。他要实现所有的visit(XXXX)方法,即实现如何处理每个ConcreteElement 角色;
Element 元素
Element 角色表示Visitor角色的访问对象,它声明了接受访问者的accept方法,accept方法接收到的参数是Visitor角色
ConcreteElement
ConcreteElement 角色负责实现 Element 角色所定义的接口,表示接受访问者的访问的接口
ObjectStructure 对象结构
ObjectStruecture 角色负责处理 Element 角色的集合,ConcreteVisitor 角色为每个Element 角色都准备了处理方法,即为了让ConcreteVisitor角色 可以遍历处理每个Element角色
类图
示例代码
以机器人升级代码为例
机器人
public class EggRobot {
private CPU cpu;
private HardDisk hardDisk;
public EggRobot(CPU cpu, HardDisk hardDisk) {
this.cpu = cpu;
this.hardDisk = hardDisk;
}
public void cal() {
cpu.run();
hardDisk.run();
}
public void update(Visitor visitor) {
cpu.accept(visitor);
hardDisk.accept(visitor);
}
}
硬件类:相当于Element
public abstract class HardWare {
protected String command;
public HardWare(String command) {
this.command = command;
}
public abstract void accept(Visitor visitor);
public abstract void run();
}
CPU:相当于ConcreteElement
public class CPU extends HardWare{
public CPU(String command) {
super(command);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public void run() {
System.out.println(command);
}
}
HardDisk:相当于ConcretrElement
public class HardDisk extends HardWare{
public HardDisk(String command) {
super(command);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public void run() {
System.out.println(command);
}
}
Visitor:接口
public interface Visitor {
void visit(HardDisk hardDisk);
void visit(CPU cpu);
}
ConcreteVisitor:具体访问者
public class UpdateVisitor implements Visitor{
@Override
public void visit(HardDisk hardDisk) {
hardDisk.command += "1";
}
@Override
public void visit(CPU cpu) {
cpu.command += "2";
}
}
功能分析
双重分发
accept 方法调用如下
element.accept(visitor)
而 visit 方法调用如下
visitor.visit(element)
这两个方法是相反的关系,element 接收 visitor,而 visitor 又访问 element
在Visitor 模式中,ConcreteElement 和 ConcreteVisitor 这两个角色共同决定了实际进行的处理。
模式目的
Visitor 模式的目的是将处理从数据结构中分离出来,保存数据结构和以数据结构为基础进行处理是两种不同的东西
符合开闭原则
在不修改现有代码的前提下进行扩展
很容易增加 ConcreteVisitor 角色,完全不用修改 ConcreteElement 角色
但是难以增加 ConcreteElment 角色,因为增加该角色,那么visitor角色中就会多增加一个接口,则让其所有的子类都要重写该方法