访问者模式

69 阅读2分钟

背景

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 模式中,ConcreteElementConcreteVisitor 这两个角色共同决定了实际进行的处理。

模式目的

Visitor 模式的目的是将处理从数据结构中分离出来,保存数据结构和以数据结构为基础进行处理是两种不同的东西

符合开闭原则

在不修改现有代码的前提下进行扩展

很容易增加 ConcreteVisitor 角色,完全不用修改 ConcreteElement 角色

但是难以增加 ConcreteElment 角色,因为增加该角色,那么visitor角色中就会多增加一个接口,则让其所有的子类都要重写该方法