设计模式:访问者模式

 意图

访问者模式(Visitor)是一种行为设计模式 它能将算法与其所作用的对象隔离开来

访问者模式结构

访问者设计模式的结构

访问者 Visitor 接口声明了一系列以对象结构的具体元素为参数的访问者方法 如果编程语言支持重载 这些方法的名称可以是相同的 但是其参数一定是不同的

具体访问者 Concrete Visitor) 会为不同的具体元素类实现相同行为的几个不同版本。

元素 Element) 接口声明了一个方法来 接收 访问者。 该方法必须有一个参数被声明为访问者接口类型。

具体元素 Concrete Element) 必须实现接收方法。 该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。 请注意, 即使元素基类实现了该方法, 所有子类都必须对其进行重写并调用访问者对象中的合适方法。

客户端 Client) 通常会作为集合或其他复杂对象 例如一个组合树) 的代表。 客户端通常不知晓所有的具体元素类, 因为它们会通过抽象接口与集合中的对象进行交互。

访问者模式适合应用场景

  • 如果你需要对一个复杂对象结构 例如对象树 中的所有元素执行某些操作 可使用访问者模式

访问者模式通过在访问者对象中为多个目标类提供相同操作的变体 让你能在属于不同类的一组对象上执行同一操作

  • 可使用访问者模式来清理辅助行为的业务逻辑

该模式会将所有非主要的行为抽取到一组访问者类中 使得程序的主要类能更专注于主要的工作

  • 当某个行为仅在类层次结构中的一些类中有意义 而在其他类中没有意义时 可使用该模式

你可将该行为抽取到单独的访问者类中 只需实现接收相关类的对象作为参数的访问者方法并将其他方法留空即可

访问者模式优缺点

优点:

  •  开闭原则 你可以引入在不同类对象上执行的新行为 且无需对这些类做出修改
  •  单一职责原则 可将同一行为的不同版本移到同一个类中
  •  访问者对象可以在与各种对象交互时收集一些有用的信息 当你想要遍历一些复杂的对象结构 例如对象树 并在结构中的每个对象上应用访问者时 这些信息可能会有所帮助

缺点:

  •  每次在元素层次结构中添加或移除一个类时 你都要更新所有的访问者
  •  在访问者同某个元素进行交互时 它们可能没有访问元素私有成员变量和方法的必要权限

与其他模式的关系

在 Java 中使用模式

使用示例 访问者不是常用的设计模式 因为它不仅复杂 应用范围也比较狭窄

这里是 Java 程序库代码中该模式的一些示例

示例代码

访问者 Visitor

public interface ComputerPartVisitor {
  void visit(Computer computer);
  void visit(Mouse mouse);
  void visit(Keyboard keyboard);
  void visit(Monitor monitor);
}

 具体访问者 Concrete Visitor

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
  @Override
  public void visit(Computer computer) {
    System.out.println("Displaying Computer.");
  }

  @Override
  public void visit(Mouse mouse) {
    System.out.println("Displaying Mouse.");
  }

  @Override
  public void visit(Keyboard keyboard) {
    System.out.println("Displaying Keyboard.");
  }

  @Override
  public void visit(Monitor monitor) {
    System.out.println("Displaying Monitor.");
  }
}

 元素 Element

public interface ComputerPart {
  void accept(ComputerPartVisitor computerPartVisitor);
}

具体元素 Concrete Element

public class Keyboard implements ComputerPart {
  @Override
  public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
  }
}
public class Mouse implements ComputerPart {
  @Override
  public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
  }
}
public class Monitor implements ComputerPart {
  @Override
  public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
  }
}
public class Computer implements ComputerPart {
  private final ComputerPart[] parts;

  public Computer() {
    parts = new ComputerPart[]{new Mouse(), new Keyboard(), new Monitor()};
  }

  @Override
  public void accept(ComputerPartVisitor computerPartVisitor) {
    for (ComputerPart part : parts) {
      part.accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
  }
}

客户端 Client

public class Client {
  public static void main(String[] args) {
    ComputerPart computer = new Computer();
    computer.accept(new ComputerPartDisplayVisitor());
  }
}