概念

  • 将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
  • image.png

主要角色

  • 抽象访问者(Visitor)角色:
    • 定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  • 具体访问者(ConcreteVisitor)角色:
    • 实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  • 抽象元素(Element)角色:
    • 声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  • 具体元素(ConcreteElement)角色:
    • 实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  • 对象结构(Object Structure)角色:
    • 是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
  1. /**
  2. * 抽象访问者(Visitor)角色
  3. */
  4. public interface Vistor {
  5. //访问者能访问元素。
  6. void visitDisk(Disk disk);
  7. void visitCPU(CPU cpu);
  8. void visitFoot(Foot foot);
  9. }
/**
 * 具体访问者(ConcreteVisitor)角色
 */
public class UpdatePackage implements Vistor{


    private String ext;
    public  UpdatePackage(String ext){
        this.ext = ext;
    }

    @Override
    public void visitDisk(Disk disk) {
        disk.command += " >>> "+ext;
    }

    @Override
    public void visitCPU(CPU cpu) {
        //改属性为例
        cpu.command += ">>>> "+ext;
        //装饰模式。改方法
    }

    @Override
    public void visitFoot(Foot foot) {
        foot.command += " >>>> "+ext;
    }
}
/**
 * 抽象元素(Element)角色
 */
public  abstract class Hardware {
    String command;//封装硬件的处理指令

    public Hardware(String command){
        this.command = command;
    }


    //收到命令以后进行工作
    abstract public void work();

    //定义接受软件升级包的方法。这个方法应该具体硬件去实现
     abstract public void accept(Vistor vistor);
}
/**
 * 具体元素(ConcreteElement)角色
 */
public class CPU  extends Hardware{
    public CPU(String command) {
        super(command);
    }

    @Override
    public void work() {
        System.out.println("CPU处理指令:"+command);
    }

    @Override
    public void accept(Vistor vistor) {
        //给升级包提供一个改CPU指令等信息的办法
        vistor.visitCPU(this);
    }

}

/**
 * 具体元素(ConcreteElement)角色
 */
public class Disk extends Hardware{
    public Disk(String command) {
        super(command);
    }

    @Override
    public void work() {
        System.out.println("Disk保存指令的历史记录:"+command);
    }


    @Override
    public void accept(Vistor vistor) {
        vistor.visitDisk(this);
    }

}

/**
 * 具体元素(ConcreteElement)角色
 */
public class Foot extends Hardware{
    public Foot(String command) {
        super(command);
    }

    @Override
    public void work() {
        System.out.println("脚处理指令:"+command);
    }


    //元素需要接受一个访问者的访问
    @Override
    public void accept(Vistor vistor) {
        vistor.visitFoot(this);
    }
}
/**
 * 对象结构(Object Structure)角色
 */
public class XiaoAi {

    private CPU cpu = new CPU("武汉天气");
    private Disk disk = new Disk("武汉天气");
    private Foot foot = new Foot("武汉天气");

    void answerQuestion(){
        cpu.work();
        disk.work();
        foot.work();
    }



    //接受升级包
    public void acceptUpdate(Vistor aPackage) {

        //访问模式


        //升级CPU
        aPackage.visitCPU(cpu);
        aPackage.visitDisk(disk);
        aPackage.visitFoot(foot);

    }
}

应用场景

  • 在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。 违反依赖倒置原则。
  • 访问者模式依赖了具体类,而没有依赖抽象类
  • 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性
  • 应用于对象结构相对稳定,但其操作算法经常变化的程序。
  • Spring反射工具中的MethodVisitor是什么?