找回密码
 立即注册
首页 业界区 安全 访问者模式

访问者模式

扔飒 2025-5-30 10:37:16
访问者(Visitor)模式属于行为型模式的一种。
访问者模式主要用于分离算法和对象结构,从而在不修改原有对象的情况下扩展新的操作。它适用于数据结构相对稳定,而操作(行为)容易变化的场景。
访问者模式允许在不修改现有类的情况下,为类层次结构中的对象定义新的操作
访问者模式通过将操作封装到一个独立的类(即访问者)中,使得对象结构与操作解耦。
访问者模式使用了一种名为双分派(在运行时根据两个对象的类型动态选择方法)的技巧。
Java标准库中的 FileVisitor,就是使用的访问者模式。访问者模式的设计比较复杂。
访问者模式适用于以下场景:

  • 数据结构相对稳定,但操作易变的系统(例如编译器、代码分析器)。
  • 需要对对象结构进行不同操作,并且这些操作相对独立,例如报表生成、统计、数据转换。
访问者模式通常有以下组成部分:

  • Visitor(访问者):定义一个访问接口,为不同类型的元素提供不同的访问方法。
  • ConcreteVisitor(具体访问者):访问者的具体实现,具体执行操作。
  • Element(元素接口):定义一个 accept(Visitor v) 方法,允许 Visitor 访问自身。
  • ConcreteElement(具体元素):具体的对象结构,实现 Element 接口,并在 accept(Visitor v) 方法中进行调用。
  • ObjectStructure(对象结构,通常是元素的集合):维护一组 Element 对象,并提供 accept(Visitor v) 方法,让访问者访问所有的元素。
我们模拟一下访问者模式的实现。
1、定义访问者接口
  1. // 访问者接口
  2. interface Visitor {
  3.     void visit(ConcreteElementA elementA);
  4.     void visit(ConcreteElementB elementB);
  5. }
复制代码
1.gif
2、定义具体访问者
  1. // 具体访问者1
  2. class ConcreteVisitor1 implements Visitor {
  3.     @Override
  4.     public void visit(ConcreteElementA elementA) {
  5.         System.out.println("Visitor1 访问 " + elementA.getName());
  6.     }
  7.     @Override
  8.     public void visit(ConcreteElementB elementB) {
  9.         System.out.println("Visitor1 访问 " + elementB.getName());
  10.     }
  11. }
  12. // 具体访问者2
  13. class ConcreteVisitor2 implements Visitor {
  14.     @Override
  15.     public void visit(ConcreteElementA elementA) {
  16.         System.out.println("Visitor2 访问 " + elementA.getName());
  17.     }
  18.     @Override
  19.     public void visit(ConcreteElementB elementB) {
  20.         System.out.println("Visitor2 访问 " + elementB.getName());
  21.     }
  22. }
复制代码
2.gif
3、定义元素接口
  1. // 元素接口
  2. interface Element {
  3.     void accept(Visitor visitor);
  4. }
复制代码
3.gif
4、定义具体元素
  1. // 具体元素 A
  2. class ConcreteElementA implements Element {
  3.     private String name = "ElementA";
  4.     @Override
  5.     public void accept(Visitor visitor) {
  6.         visitor.visit(this);
  7.     }
  8.     public String getName() {
  9.         return name;
  10.     }
  11. }
  12. // 具体元素 B
  13. class ConcreteElementB implements Element {
  14.     private String name = "ElementB";
  15.     @Override
  16.     public void accept(Visitor visitor) {
  17.         visitor.visit(this);
  18.     }
  19.     public String getName() {
  20.         return name;
  21.     }
  22. }
复制代码
4.gif
5、定义对象结构
  1. // 对象结构,包含多个元素
  2. class ObjectStructure {
  3.     private List<Element> elements = new ArrayList<>();
  4.     public void addElement(Element element) {
  5.         elements.add(element);
  6.     }
  7.     public void accept(Visitor visitor) {
  8.         for (Element element : elements) {
  9.             element.accept(visitor);
  10.         }
  11.     }
  12. }
复制代码
5.gif
6、测试访问者模式
  1. public class VisitorPatternDemo {
  2.     public static void main(String[] args) {
  3.         ObjectStructure structure = new ObjectStructure();
  4.         // 添加元素
  5.         structure.addElement(new ConcreteElementA());
  6.         structure.addElement(new ConcreteElementB());
  7.         // 使用不同的访问者访问元素
  8.         Visitor visitor1 = new ConcreteVisitor1();
  9.         Visitor visitor2 = new ConcreteVisitor2();
  10.         System.out.println("使用 Visitor1 访问:");
  11.         structure.accept(visitor1);
  12.         System.out.println("\n使用 Visitor2 访问:");
  13.         structure.accept(visitor2);
  14.     }
  15. }
复制代码
6.gif
访问者模式的优缺点
优点:

  • 遵循开闭原则(OCP):可以在不修改元素类的情况下,为其添加新的操作。
  • 将数据结构与行为分离:对象结构负责管理元素,而行为由访问者独立实现,增强了灵活性。
  • 适用于复杂对象结构:当对象结构中包含不同类型的元素时,访问者模式可以统一管理操作逻辑。
缺点:

  • 代码复杂度增加:对于简单对象结构,使用访问者模式可能会增加不必要的复杂性。
  • 每次在元素层次结构中添加或移除一个类时,都要更新所有的访问者。
我们可以将访问者模式视为命令模式的加强版本,其对象可对不同类的多种对象执行操作。
至此23种设计模式暂告一个段落了。我们将开启下个篇章。
只有读不完的书,哪有不会走的人。-- 烟沙九洲

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册