2023-7-20-第二十一式访问者模式

简介: 2023-7-20-第二十一式访问者模式

😉一、基础概念

访问者模式(Visitor Pattern)是一种行为型设计模式,通过将算法的操作从数据结构中分离出来,使得可以在不改变数据结构的情况下定义新的操作。该模式允许您对一组对象执行特定操作,而无需修改这些对象的类。

在访问者模式中,有两个主要角色:

  1. 访问者(Visitor):定义了对各种元素对象的操作方法,每个操作都可以根据具体的元素类型执行不同的逻辑。
  2. 元素(Element):表示被访问的对象,提供一个接受访问者的方法,该方法将调用访问者的适当操作。

访问者模式的核心思想是将操作和数据结构分离,以便于增加新的操作而无需修改现有的数据结构。这种模式适用于当对数据结构进行的操作需要改变时,但是数据结构本身却保持稳定。

使用访问者模式的主要优点包括:

  • 可以增加新的操作,而无需修改现有的元素类。
  • 将相关的操作集中在访问者类中,使代码更易维护和理解。
  • 可以对数据结构进行复杂的操纵,而无需在元素类中添加大量的方法。

然而,访问者模式也有一些缺点,例如:

  • 增加新的元素类比较困难,因为每个访问者类都必须与所有的元素类进行交互。
  • 可能会破坏封装性,因为访问者需要访问元素的内部状态。

总之,访问者模式提供了一种遍历数据结构并对其执行操作的灵活方式。它可以帮助我们将操作与数据结构解耦,并使代码更易于扩展和维护。


🐱‍🐉二、访问者模式实现

在C++中,可以使用访问者模式来实现对一组对象执行特定操作的场景。下面是一个简单的示例:

#include <iostream>
#include <vector>
// 前向声明 ElementA 和 ElementB 类
class ElementA;
class ElementB;
// 定义 Visitor 抽象基类
class Visitor {
public:
    virtual void visit(ElementA* element) = 0;
    virtual void visit(ElementB* element) = 0;
};
// 定义 Element 抽象基类
class Element {
public:
    virtual void accept(Visitor* visitor) = 0;
};
// 具体元素类 ElementA
class ElementA : public Element {
public:
    void accept(Visitor* visitor) override {
        visitor->visit(this);
    }
    void operationA() {
        std::cout << "Performing operation A on ElementA" << std::endl;
    }
};
// 具体元素类 ElementB
class ElementB : public Element {
public:
    void accept(Visitor* visitor) override {
        visitor->visit(this);
    }
    void operationB() {
        std::cout << "Performing operation B on ElementB" << std::endl;
    }
};
// 具体的访问者类 ConcreteVisitor
class ConcreteVisitor : public Visitor {
public:
    void visit(ElementA* element) override {
        element->operationA();
    }
    void visit(ElementB* element) override {
        element->operationB();
    }
};
int main() {
    // 创建具体元素对象
    ElementA elementA;
    ElementB elementB;
    // 创建访问者对象
    ConcreteVisitor concreteVisitor;
    // 使用访问者访问元素对象
    elementA.accept(&concreteVisitor);
    elementB.accept(&concreteVisitor);
    return 0;
}

在这个示例中,我们定义了Visitor抽象基类和具体的访问者类ConcreteVisitor。同时,定义了Element抽象基类和具体元素类ElementAElementB。元素类通过实现accept()方法来接受访问者的访问。

当访问者访问元素时,元素会将自身作为参数传递给访问者的对应方法。访问者根据元素的类型执行相应的操作。在示例中,ConcreteVisitorvisit()方法分别执行了ElementAElementB的特定操作。

在主函数中,我们创建了具体的元素对象,并创建了具体的访问者对象。然后使用访问者对象访问元素对象,从而触发相应的操作。

运行此示例会输出以下内容:

Performing operation A on ElementA
Performing operation B on ElementB

这表明访问者模式成功地将特定操作与元素对象解耦,并通过访问者对象来执行操作。


🎉三、模块之间的关系

在访问者模式中,有多个关键组件之间的关系。下面是各个组件之间的关系说明:

  1. Visitor(访问者):访问者是一个抽象基类或接口,定义了一组访问操作方法,每个方法对应于元素类中的一种具体操作。访问者可以通过这些方法访问和处理不同类型的元素对象。
  2. ConcreteVisitor(具体访问者):具体访问者是 Visitor 的实现类,它实现了 Visitor 定义的所有访问操作方法。每个具体访问者类负责执行特定的操作逻辑。
  3. Element(元素):元素是一个抽象基类或接口,定义了一个 accept() 方法,该方法接收一个访问者对象作为参数,并在其中调用访问者的对应方法。元素类将自身作为参数传递给访问者的方法,以便访问者可以对其进行操作。
  4. ConcreteElement(具体元素):具体元素是 Element 的实现类,它实现了 Element 定义的 accept() 方法,并根据需要提供其他操作方法。具体元素类通过实现 accept() 方法,将自身传递给访问者对象进行访问。
  5. ObjectStructure(对象结构):对象结构是一个包含元素对象集合的类或数据结构。它提供了一种管理元素对象的方式,并且允许访问者遍历整个集合并对其中的元素进行操作。

在访问者模式中,元素对象通过接受访问者对象来实现特定操作的分离。当需要对元素执行特定操作时,访问者对象可以通过元素的 accept() 方法访问和操作元素,从而实现了解耦和灵活性。

总结起来,访问者模式的关系如下:

Visitor <|-- ConcreteVisitor
Element <|-- ConcreteElement
           ConcreteElement -- accept(Visitor)
ObjectStructure <-- Element
ConcreteElement -- performOperation()

🐱‍🚀四、注意事项

使用访问者模式时,有几个注意事项需要考虑:

  1. 增加新的元素类困难:在访问者模式中,如果需要添加新的元素类,则需要修改访问者接口和所有具体访问者的实现。这是因为每个具体访问者都需要与所有元素类进行交互。如果经常需要添加新的元素类,这可能导致代码维护方面的困难。
  2. 破坏封装性:访问者模式可能会破坏元素类的封装性。为了让访问者能够访问元素的内部状态,元素类可能需要暴露一些私有成员或提供访问方法。这可能会降低元素类的封装性和安全性。
  3. 影响可扩展性:当存在多个访问者并且每个访问者只对元素执行少量操作时,访问者模式可以很好地扩展。但是,如果一个访问者需要执行大量的操作,可能会导致访问者类变得臃肿,并且不易于维护和扩展。
  4. 遵循依赖倒置原则:在使用访问者模式时,应该遵循依赖倒置原则(Dependency Inversion Principle)。具体来说,元素应该依赖于抽象的访问者接口,而不是具体的访问者类。这样可以使得元素类与具体访问者解耦,提高代码的灵活性和可维护性。
  5. 合理使用访问者模式:访问者模式适用于操作(Visitor)和数据结构(Element)分离且需要频繁变化的场景。在其他情况下,如果只有少量固定的操作,或者操作与数据结构高度耦合,那么使用访问者模式可能会增加不必要的复杂性。

总之,虽然访问者模式可以提供一种灵活和可扩展的方式来处理对象结构中的元素操作,但也需要慎重考虑其适用性和使用方式,以避免不必要的复杂性和维护困难。


🎂五、使用场景

访问者模式适用于以下场景:

  1. 对象结构中的元素操作频繁变化:当一个对象结构中的元素类经常需要添加新的操作,而且这些操作可能会频繁地发生变化时,使用访问者模式可以将操作与元素类分离,使得添加新操作更加灵活和可扩展。
  2. 操作与数据结构分离:如果需要对一个对象结构中的元素执行不同的操作,并且希望将操作与元素类解耦,访问者模式提供了一种有效的方式。通过将操作定义为访问者类的方法,元素类可以接受访问者并将自身作为参数传递给访问者的方法,从而实现了操作与数据结构的分离。
  3. 集中相关操作:访问者模式可以将相关的操作集中在一个访问者类中,使得代码更易于维护和管理。如果有多个元素类需要执行相似或相关的操作,可以将这些操作放在一个访问者类中,并通过访问者来执行这些操作,而不需要在每个元素类中重复代码。
  4. 新增操作不影响元素类:如果需要为已有的元素类增加新的操作,并且不希望修改元素类的代码,则可以使用访问者模式。通过创建新的具体访问者类来实现新的操作,而不需要修改元素类的代码。
  5. 执行复杂操作:访问者模式适用于对数据结构进行复杂的操纵和处理的场景。通过将复杂的操作封装在访问者类中,可以使得元素类保持简单,而且可以按需调用访问者的方法来执行复杂的操作。

总之,访问者模式在需要对一个对象结构中的元素执行不同操作,并且希望将操作与元素类解耦的情况下,提供了一种优雅且可扩展的设计方案。


🍳参考文献

🧊文章总结

提示:这里对文章进行总结:

   本文讲了关于访问者模式的知识。


目录
相关文章
|
7月前
|
设计模式 算法 编译器
C++访问者模式:设计与应用之美
C++访问者模式:设计与应用之美
60 0
|
7月前
|
设计模式 算法 Java
小谈设计模式(29)—访问者模式
小谈设计模式(29)—访问者模式
|
7月前
|
设计模式 Java
小谈设计模式(21)—迭代器模式
小谈设计模式(21)—迭代器模式
|
XML 存储 设计模式
2023-7-26-第二十三式解释器模式
2023-7-26-第二十三式解释器模式
91 0
|
设计模式 存储 算法
2023-7-8-第十四式策略模式
2023-7-8-第十四式策略模式
88 0
|
7月前
|
设计模式 算法 Java
Java设计模式【二十五】:访问者模式
Java设计模式【二十五】:访问者模式
43 0
|
设计模式 数据库
几张图带你手拿把掐设计模式六大原则
几张图带你手拿把掐设计模式六大原则
80 0
|
设计模式 调度 C++
2023-7-14-第十九式中介者模式
2023-7-14-第十九式中介者模式
72 0
|
设计模式 存储 算法
2023-7-19-第二十式迭代器模式
2023-7-19-第二十式迭代器模式
79 0
|
设计模式 C++
2023-7-11-第十六式职责链模式
2023-7-11-第十六式职责链模式
68 0