【设计模式系列笔记】访问者模式

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 访问者模式是一种行为设计模式,旨在将算法与对象结构分离,使得能够在不修改元素类的前提下定义新的操作。这一模式的核心思想是在元素类中添加一个接受访问者的方法,从而实现在不同元素上执行不同操作的能力。

1. 访问者模式介绍

访问者模式是一种行为设计模式,旨在将算法与对象结构分离,使得能够在不修改元素类的前提下定义新的操作。这一模式的核心思想是在元素类中添加一个接受访问者的方法,从而实现在不同元素上执行不同操作的能力。

主要角色:

  1. 元素接口(Element): 定义了一个accept方法,该方法接受一个访问者对象作为参数,从而让访问者能够访问这个元素。
  2. 具体元素类(ConcreteElement): 实现了元素接口的具体类,同时包含了具体的业务逻辑。
  3. 访问者接口(Visitor): 定义了访问者能够访问各种具体元素的方法。
  4. 具体访问者类(ConcreteVisitor): 实现了访问者接口的具体类,包含了对不同元素的具体操作逻辑。

2. 关键思想

访问者模式的关键思想是将数据结构和数据操作分离,使得可以在不修改数据结构的情况下定义新的操作。该模式的核心目标是让算法的变化不影响数据结构的稳定性。

关键思想包括以下几点:

  1. 分离数据结构和操作: 访问者模式通过在数据结构中添加一个接受访问者的方法,将数据结构和操作分离。这使得我们可以定义新的操作,而无需修改现有的数据结构。
  2. 双重分发: 在访问者模式中,有一种双重分发的机制。元素对象在接受访问者时,将自身传递给访问者,然后访问者再根据具体元素的类型调用相应的方法。这种方式实现了多态性,使得不同元素能够调用访问者的不同方法。
  3. 增加新操作的灵活性: 由于新的操作是通过增加新的访问者来实现的,而不是修改元素类,因此访问者模式使得系统更容易扩展。如果需要增加新的操作,只需要创建新的访问者而不影响现有的元素类。
  4. 适用于数据结构稳定、操作变化频繁的场景: 访问者模式适用于那些数据结构相对稳定,但对数据操作进行频繁变更的情况。这种模式使得系统更容易维护和扩展。
  5. 可维护性和可扩展性: 通过将操作移动到访问者中,访问者模式提高了系统的可维护性和可扩展性。新增的操作不会影响到已有的元素类,使得系统更加灵活。

总的来说,访问者模式的关键思想是通过在元素类中引入接受访问者的方法,实现对数据结构和操作的解耦,从而提高系统的灵活性、可维护性和可扩展性。

3. 实现方式

示例代码

// 元素接口(Element)
interface Element {
    // 接受访问者的方法
    void accept(Visitor visitor);
}
// 具体元素A类
class ConcreteElementA implements Element {
    // 实现元素接口中的accept方法
    @Override
    public void accept(Visitor visitor) {
        // 调用访问者的visitElementA方法,并将自身作为参数传递给访问者
        visitor.visitElementA(this);
    }
    // 具体元素A的特有操作
    public void operationA() {
        // 输出具体元素A的特有操作,例如:在ConcreteElementA中执行操作A
        System.out.println("在ConcreteElementA中执行操作A");
    }
}
// 具体元素B类
class ConcreteElementB implements Element {
    // 实现元素接口中的accept方法
    @Override
    public void accept(Visitor visitor) {
        // 调用访问者的visitElementB方法,并将自身作为参数传递给访问者
        visitor.visitElementB(this);
    }
    // 具体元素B的特有操作
    public void operationB() {
        // 输出具体元素B的特有操作,例如:在ConcreteElementB中执行操作B
        System.out.println("在ConcreteElementB中执行操作B");
    }
}
// 访问者接口
interface Visitor {
    // 访问具体元素A的方法
    void visitElementA(ConcreteElementA elementA);
    // 访问具体元素B的方法
    void visitElementB(ConcreteElementB elementB);
}
// 具体访问者类
class ConcreteVisitor implements Visitor {
    // 实现访问具体元素A的方法
    @Override
    public void visitElementA(ConcreteElementA elementA) {
        // 输出访问者正在对具体元素A进行操作的信息
        System.out.println("访问者正在对ConcreteElementA进行操作");
        // 调用具体元素A的特有操作
        elementA.operationA();
    }
    // 实现访问具体元素B的方法
    @Override
    public void visitElementB(ConcreteElementB elementB) {
        // 输出访问者正在对具体元素B进行操作的信息
        System.out.println("访问者正在对ConcreteElementB进行操作");
        // 调用具体元素B的特有操作
        elementB.operationB();
    }
}
// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建具体元素A
        ConcreteElementA elementA = new ConcreteElementA();
        // 创建具体元素B
        ConcreteElementB elementB = new ConcreteElementB();
        // 创建具体访问者
        ConcreteVisitor visitor = new ConcreteVisitor();
        // 具体元素A接受访问者的访问
        elementA.accept(visitor);
        // 具体元素B接受访问者的访问
        elementB.accept(visitor);
    }
}

要点:

  1. 分离操作和数据结构: 访问者模式将操作(访问者)与数据结构(元素)分离开来,使得操作可以独立变化而不影响数据结构的设计,从而提高了系统的灵活性和可维护性。
  2. 开闭原则: 通过访问者模式,可以在不修改现有元素类的情况下,增加新的操作。这符合开闭原则,即对扩展开放,对修改关闭。
  3. 增加新操作的灵活性: 访问者模式可以轻松地增加新的操作,只需要添加新的访问者类即可,不需要修改现有元素类的代码。这使得系统具有较高的可扩展性。
  4. 适用于稳定的对象结构: 访问者模式适用于对象结构相对稳定但操作频繁变化的情况。如果对象结构经常变化,可能会导致需要频繁修改访问者接口和访问者类,降低了模式的灵活性和可维护性。
  5. 复杂性: 访问者模式可能会导致系统中增加了许多访问者类和元素类,从而增加了系统的复杂性。因此,在使用访问者模式时需要权衡设计的复杂性和灵活性之间的关系。
  6. 访问者对元素的侵入性: 在访问者模式中,为了让元素能够接受访问者的访问,通常需要在元素类中添加接受访问者的方法。这使得访问者对元素的侵入性较高,增加了元素类的复杂性。

注意事项:

  1. 访问者个数: 访问者模式适用于元素稳定而操作频繁变化的场景。如果元素结构经常变化,可能会导致访问者类的数量急剧增加,不利于维护。
  2. 破坏封装: 访问者模式可能破坏元素的封装性,因为具体访问者需要访问元素的内部状态。这可能违反了一些面向对象设计的原则。
  3. 适用场景: 访问者模式在以下场景中比较适用:
  • 元素的结构相对稳定,但对元素的操作经常发生变化。
  • 需要对一个对象结构中的元素进行很多不同且不相关的操作。
  • 系统有多个稳定的数据结构,而需要对这些数据结构进行统一的操作。
  1. 使用场景限制: 访问者模式不适用于在元素类中新增操作的情况,因为新增操作需要修改所有的访问者类。

总的来说,访问者模式是一种非常有用的模式,但在使用时需要权衡灵活性和封装性,以及根据具体情况选择是否使用。

优点:

  1. 分离关注点: 访问者模式将数据结构和对数据的操作分离,使得能够独立地改变元素的操作,而不影响元素本身的结构。
  2. 增加新操作: 新的操作可以通过创建新的访问者来轻松添加,而无需修改现有的元素类。这符合开放-封闭原则,对扩展开放,对修改封闭。
  3. 可扩展性: 可以在不修改元素结构的情况下,增加新的元素类型,同时通过创建新的访问者实现对这些新元素的操作。
  4. 多态性: 访问者模式利用多态性,通过动态绑定来调用相应元素的方法,提高了代码的可读性和可维护性。
  5. 逻辑集中: 相关的操作逻辑被集中在访问者的具体实现中,使得代码更加清晰、易懂。

缺点:

  1. 破坏封装: 访问者模式可能破坏元素的封装性,因为具体访问者需要访问元素的内部状态。这可能违反了一些面向对象设计的原则。
  2. 新增元素困难: 如果元素的结构经常变化,可能会导致需要创建大量的访问者类,使得系统变得复杂且难以维护。
  3. 违反依赖倒置原则: 具体访问者通常依赖于具体元素,这可能违反依赖倒置原则,即高层模块不应该依赖于低层模块,二者都应该依赖于抽象。

应用场景:

  1. 数据结构稳定、操作变化频繁: 当数据结构相对稳定,但对数据的操作经常变化时,访问者模式是一种合适的设计选择。
  2. 复杂对象结构: 当存在一个复杂的对象结构,且需要对其进行多种不同的操作时,访问者模式可以使得操作的变化更加灵活。
  3. 代码维护性要求高: 当系统要求对元素的操作进行扩展,但不希望修改现有代码时,访问者模式提供了一种可行的解决方案。
  4. 编译器、解释器等应用: 访问者模式常用于编译器、解释器等需要对抽象语法树进行操作的场景,其中抽象语法树的节点可以看作元素,而编译或解释的操作可以看作访问者。

总的来说,访问者模式在特定场景下能够提供一种清晰的结构,使得系统更易于维护和扩展。在使用时需要权衡其优缺点,并根据具体需求选择是否使用。

目录
相关文章
|
21天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
175 37
|
21天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
9天前
|
设计模式 缓存 算法
Java设计模式-访问者模式(22)
Java设计模式-访问者模式(22)
|
5月前
|
设计模式 算法 Java
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
|
4月前
|
设计模式 网络协议 Java
技术笔记:Reactor设计模式
技术笔记:Reactor设计模式
43 0
|
4月前
|
设计模式 存储 安全
技术好文共享:设计模式笔记:单件模式(Singleton)
技术好文共享:设计模式笔记:单件模式(Singleton)
25 0
|
5月前
|
设计模式 安全 Java
【设计模式】字节三面:请举例阐释访问者模式
【设计模式】字节三面:请举例阐释访问者模式
34 2
|
5月前
|
设计模式
【设计模式】张一鸣笔记:责任链接模式怎么用?
【设计模式】张一鸣笔记:责任链接模式怎么用?
40 1
|
5月前
|
设计模式 算法 Java
【设计模式系列笔记】设计模式与设计原则
设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 设计原则是一些通用的设计指导方针,它们提供了如何设计一个优秀的软件系统的基本思想和规则。指导着设计者如何组织代码以实现高内聚、低耦合、易扩展和易维护的软件系统。
65 4
|
5月前
|
设计模式 JavaScript 前端开发
vue的设计模式_笔记
vue的设计模式_笔记
41 0