什么是访问者模式?

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

访问者模式能把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构,这提高了程序的扩展性和灵活性。

适用场景

在现实生活中,有些集合对象存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。例如,公园中存在多个景点,也存在多个游客,不同的游客对同一个景点的评价可能不同;医院医生开的处方单中包含多种药元素,査看它的划价员和药房工作人员对它的处理方式也不同,划价员根据处方单上面的药品名和数量进行划价,药房工作人员根据处方单的内容进行抓药。电影或电视剧中的人物角色,不同的观众对他们的评价也不同;还有顾客在商场购物时放在“购物车”中的商品,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。

代码实现

访问者模式包含以下主要角色。

  1. 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
  2. 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  3. 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
  4. 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  5. 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。 ```java import java.util.ArrayList; import java.util.List;

/**

  • 抽象访问者 */ interface Visitor { //访问元素 void visit(Element element); }

/**

  • 具体访问者A类 */ class VisitorA implements Visitor { @Override public void visit(Element element) {
    1. System.out.println("访问者A访问并操作...");
    } }

/**

  • 具体访问者B类 */ class VisitorB implements Visitor { @Override public void visit(Element element) {

    1. System.out.println("访问者B访问并操作...");

    } }

/**

  • 抽象元素类 */ interface Element { //允许访问 void accept(Visitor visitor); }

/**

  • 具体元素A类 */ class ElementA implements Element { @Override public void accept(Visitor visitor) {
    1. System.out.println("元素A");
    2. visitor.visit(this);
    } }

/**

  • 具体元素B类 */ class ElementB implements Element { @Override public void accept(Visitor visitor) {
    1. System.out.println("元素B");
    2. visitor.visit(this);
    } }

/**

  • 对象结构角色 */ class ObjectStructure { private final List list = new ArrayList<>();

    public void accept(Visitor visitor) {

    1. for (Element element : list) {
    2. element.accept(visitor);
    3. }

    }

    public void add(Element element) {

    1. list.add(element);

    }

    public void remove(Element element) {

    1. list.remove(element);

    } }

/**

  • 访问者模式 测试类 */ public class VisitorPattern { public static void main(String[] args) {

    1. ObjectStructure os = new ObjectStructure();
    2. //添加元素
    3. os.add(new ElementA());
    4. os.add(new ElementB());
    5. //允许访问者访问
    6. os.accept(new VisitorA());
    7. System.out.println("------------------------");
    8. os.accept(new VisitorB());
    9. //输出:
    10. //元素A
    11. //访问者A访问并操作...
    12. //元素B
    13. //访问者A访问并操作...
    14. //------------------------
    15. //元素A
    16. //访问者B访问并操作...
    17. //元素B
    18. //访问者B访问并操作...

    } } ```