Java 访问者模式详解

162 阅读3分钟

访问者模式(Visitor Pattern)是一种行为型设计模式,它分离了对象结构和操作,并且可以在不改变对象结构的前提下,定义新的操作。

在实际开发中,经常需要对一个对象结构中的所有元素进行遍历,同时根据不同的元素类型执行不同的操作,比如编译器对抽象语法树的遍历就应用了访问者模式。

Java 访问者模式由四个部分组成:抽象访问者(Visitor)、具体访问者(ConcreteVisitor)、抽象元素(Element)和具体元素(ConcreteElement)。其中,抽象元素和具体元素组成了对象结构,抽象访问者和具体访问者定义了对对象结构的操作。

下面我们将从以下几个方面介绍 Java 访问者模式的实现:

  1. 抽象元素

抽象元素(Element)是对象结构中所有元素的抽象父类,其中定义了接收访问者的方法 accept。

public interface Element {
    void accept(Visitor visitor);
}
  1. 具体元素

具体元素(ConcreteElement)是抽象元素的具体实现类,其中实现了 accept 方法,将自身作为参数传递给访问者。

public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
  1. 抽象访问者

抽象访问者(Visitor)是对对象结构中所有元素进行操作的抽象父类,其中定义了 visit 方法,用于根据具体元素类型执行不同的操作。

public interface Visitor {
    void visit(ConcreteElementA elementA);
    void visit(ConcreteElementB elementB);
}
  1. 具体访问者

具体访问者(ConcreteVisitor)是抽象访问者的具体实现类,其中实现了 visit 方法,根据具体元素类型执行不同的操作。

public class ConcreteVisitor1 implements Visitor {
    @Override
    public void visit(ConcreteElementA elementA) {
        System.out.println("ConcreteVisitor1 visit ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB elementB) {
        System.out.println("ConcreteVisitor1 visit ConcreteElementB");
    }
}
public class ConcreteVisitor2 implements Visitor {
    @Override
    public void visit(ConcreteElementA elementA) {
        System.out.println("ConcreteVisitor2 visit ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB elementB) {
        System.out.println("ConcreteVisitor2 visit ConcreteElementB");
    }
}
  1. 对象结构

对象结构(Object Structure)是包含一组具体元素的容器,其中可以遍历所有元素并接受访问者进行操作。

public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void removeElement(Element element) {
        elements.remove(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

使用时,我们可以先创建一组具体元素,然后将它们添加到对象结构中,并创建一组具体访问者进行操作。

public class Client {
    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(new ConcreteElementA());
        objectStructure.addElement(new ConcreteElementB());

        Visitor visitor1 = new ConcreteVisitor1();
        Visitor visitor2 = new ConcreteVisitor2();

        objectStructure.accept(visitor1);
        objectStructure.accept(visitor2);
    }
}

输出结果如下:

ConcreteVisitor1 visit ConcreteElementA
ConcreteVisitor1 visit ConcreteElementB
ConcreteVisitor2 visit ConcreteElementA
ConcreteVisitor2 visit ConcreteElementB

总的来说,访问者模式通过分离对象结构和操作,使得增加新的操作不会影响到对象结构,同时也使得操作本身更加清晰明了。但是,在实际开发中,如果对象结构或具体访问者非常庞大,将会导致访问者模式难以维护,因此应该根据具体情况进行权衡和选择。