设计模式|访问者模式(Visitor Pattern)

发布于:2024-04-17 ⋅ 阅读:(20) ⋅ 点赞:(0)


访问者模式是一种行为设计模式,它允许在不改变已有类的情况下定义一组新的操作。
这些操作通常分散在不同的类中,但是希望能够对这些类的对象进行统一的处理。
访问者模式的核心思想是将操作从对象结构中分离出来,使得可以在不改变这些对象的前提下定义新的操作。

结构

访问者模式的结构包括以下主要组成部分:

  1. 抽象元素(Element):
  • 定义了一个接口,声明了接受访问者对象的accept方法,该方法通常以访问者作为参数。抽象元素可以是一个接口或抽象类,它定义了访问者可以访问的对象的通用接口。
  1. 具体元素(ConcreteElement):
  • 实现了抽象元素接口,提供了具体的实现,包含了具体的业务逻辑。每个具体元素都必须实现accept方法,该方法将自身作为参数传递给访问者。
  1. 抽象访问者(Visitor):
  • 定义了一个访问接口,声明了一组访问方法,每个方法对应一个具体元素的访问操作。抽象访问者可以是一个接口或抽象类,它定义了访问者可以执行的操作。
  1. 具体访问者(ConcreteVisitor):
  • 实现了抽象访问者接口,提供了具体的访问操作。每个具体访问者都必须实现抽象访问者中声明的所有访问方法,以便对具体元素进行访问。
  1. 对象结构(Object Structure):
  • 包含了一组具体元素对象,可以是一个集合、列表、树等数据结构。对象结构通常提供了一个接口或方法来允许访问者访问其中的元素。

通过以上组成部分的协作,访问者模式实现了对一个对象结构中的元素进行多种不同操作的能力,同时又保持了元素类和操作的解耦合。

举例

  1. 动物园游客参观动物: 想象你去动物园参观,动物园中有许多不同的动物,比如狮子、大象、长颈鹿等。你可以作为一个访问者,对每种动物进行不同的操作,比如观察、喂食、拍照等。这里的动物就是对象结构,而你的行为就是访问者模式中的访问者,可以对不同的动物执行不同的操作。
  2. 超市购物: 当你去超市购物时,你可能会购买不同种类的商品,比如水果、蔬菜、零食等。你可以把超市看作是一个对象结构,不同种类的商品是其中的元素,而你的购物清单就是访问者模式中的访问者,可以对不同种类的商品执行不同的操作,比如购买、放回货架等。
  3. 家庭医生给病人检查: 假设你去看家庭医生,医生可能会对你进行身体检查,比如量体温、听心跳、观察症状等。在这个例子中,你是医生的访问者,医生是对象结构,而不同的检查项目是医生可以执行的操作。

这些例子虽然简单,但可以帮助理解访问者模式的基本概念:访问者可以对一个对象结构中的元素执行不同的操作,而不需要修改元素的类。

优缺点

优点

  1. 分离关注点:访问者模式将数据结构和对数据结构的操作分离开来,使得各自的变化不会影响到对方,从而实现了关注点的分离。
  2. 新功能扩展方便:通过添加新的访问者类,可以很方便地在不改变现有类的情况下,扩展对数据结构的操作。
  3. 符合开闭原则:访问者模式通过在不改变现有代码的情况下,添加新的操作,符合开闭原则,使得系统更加容易扩展和维护。

缺点

  1. 增加新的元素类困难:如果要在系统中添加新的元素类,需要修改所有的访问者类,以便它们能够处理新的元素类。这违背了开闭原则,使得系统的扩展性降低。
  2. 破坏封装:访问者模式将数据结构的内部细节暴露给了访问者类,破坏了数据结构的封装性,使得数据结构更加脆弱。
  3. 可读性降低:访问者模式会导致系统中的类和类之间的关系变得更加复杂,降低了代码的可读性和可维护性。

综合考虑,访问者模式适用于对数据结构中的元素进行多种不同的操作,且数据结构的类层次比较稳定的情况下。但是,需要注意其可能带来的缺点,特别是在系统需要频繁扩展新的元素类时,可能会增加系统的维护成本。

代码示例

假设有一个几何图形类层次结构,包括圆形(Circle)和矩形(Rectangle),我们想要实现两种不同的操作:计算图形的面积和计算图形的周长。

首先,定义几何图形的接口和两种不同的访问者:

// 几何图形接口
interface Shape {
   
    void accept(Visitor visitor);
}

// 圆形类
class Circle implements Shape {
   
    private double radius;

    public Circle(double radius)