C++ 设计模式:访问者模式(Visitor Pattern)

链接:C++ 设计模式
链接:C++ 设计模式 - 命令模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变元素类的前提下,定义作用于这些元素的新操作。访问者模式将操作的逻辑从元素类中分离出来,使得新的操作可以很容易地添加,而不需要修改元素类的代码。

1. 问题分析

在开发中,由于需求的改变,某些类层次结构经常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计,违反开闭原则(OCP)。

访问者模式通过将操作封装到访问者对象中,使得新的操作可以很容易地添加,而不需要修改元素类的代码。元素类只需要接受访问者,并将自己传递给访问者。

2.实现步骤

  1. 定义访问者接口(Visitor):声明对每个具体元素类的访问操作。
  2. 实现具体访问者类(ConcreteVisitor):实现访问者接口,定义具体的访问操作。
  3. 定义元素接口(Element):声明接受访问者的方法。
  4. 实现具体元素类(ConcreteElement):实现元素接口,定义接受访问者的方法,并将自己传递给访问者。
  5. 定义对象结构类(ObjectStructure):包含元素的集合,可以遍历这些元素并让访问者访问它们。

3.代码示例

3.1.定义访问者接口

cpp 复制代码
// 前向声明具体元素类
class ConcreteElementA;
class ConcreteElementB;

// 访问者接口
class Visitor {
 public:
  virtual ~Visitor() = default;
  virtual void visitConcreteElementA(ConcreteElementA* element) = 0;
  virtual void visitConcreteElementB(ConcreteElementB* element) = 0;
};

3.2.定义元素接口

cpp 复制代码
// 元素接口
class Element {
 public:
  virtual ~Element() = default;
  virtual void accept(Visitor* visitor) = 0;
};

3.3.实现具体元素类

cpp 复制代码
// 具体元素类A
class ConcreteElementA : public Element {
 public:
  void accept(Visitor* visitor) override { visitor->visitConcreteElementA(this); }
};
cpp 复制代码
// 具体元素类B
class ConcreteElementB : public Element {
 public:
  void accept(Visitor* visitor) override { visitor->visitConcreteElementB(this); }
};

3.4. 实现具体访问者类

cpp 复制代码
// 具体访问者类1:执行操作1
class ConcreteVisitor1 : public Visitor {
 public:
  void visitConcreteElementA(ConcreteElementA* element) override {
    std::cout << "ConcreteVisitor1: Processing ConcreteElementA" << std::endl;
  }

  void visitConcreteElementB(ConcreteElementB* element) override {
    std::cout << "ConcreteVisitor1: Processing ConcreteElementB" << std::endl;
  }
};
cpp 复制代码
// 具体访问者类2:执行操作2
class ConcreteVisitor2 : public Visitor {
 public:
  void visitConcreteElementA(ConcreteElementA* element) override {
    std::cout << "ConcreteVisitor2: Processing ConcreteElementA" << std::endl;
  }

  void visitConcreteElementB(ConcreteElementB* element) override {
    std::cout << "ConcreteVisitor2: Processing ConcreteElementB" << std::endl;
  }
};

3.5. 定义对象结构类

cpp 复制代码
// 对象结构类
class ObjectStructure {
 public:
  void addElement(Element* element) { elements_.push_back(element); }

  void accept(Visitor* visitor) {
    for (Element* element : elements_) {
      element->accept(visitor);
    }
  }

 private:
  std::vector<Element*> elements_;
};

3.6. 客户端代码

cpp 复制代码
int main() {
  // 创建对象结构
  ObjectStructure objectStructure;

  // 创建具体元素
  ConcreteElementA elementA;
  ConcreteElementB elementB;

  // 添加元素到对象结构
  objectStructure.addElement(&elementA);
  objectStructure.addElement(&elementB);

  // 创建具体访问者
  ConcreteVisitor1 visitor1;
  ConcreteVisitor2 visitor2;

  // 访问者访问对象结构中的元素
  std::cout << "Visitor1 visiting elements:" << std::endl;
  objectStructure.accept(&visitor1);

  std::cout << "Visitor2 visiting elements:" << std::endl;
  objectStructure.accept(&visitor2);

  return 0;
}

4.总结

  1. 优点
    • 扩展性:可以很容易地增加新的访问者,而无需修改元素类的代码。
    • 单一职责原则:将不同的操作分离到不同的访问者中,使得每个访问者只负责一种操作。
    • 开闭原则:元素类对扩展开放,对修改关闭。
  2. 缺点
    • 元素类的修改:每次增加新的元素时,都需要修改所有的访问者类,所以该模式的前提是元素类是稳定的。
    • 复杂性:如果元素类和访问者类较多,代码会变得复杂。
相关推荐
ttod_qzstudio37 分钟前
【软考设计模式】备忘录模式:对象状态的捕获与无损恢复精讲
设计模式·备忘录模式
ttod_qzstudio1 小时前
【软考设计模式】责任链模式:请求传递的多级处理与发送接收解耦精讲
设计模式·责任链模式
charlie1145141911 小时前
Cinux: 为大内核铺路
开发语言·c++·操作系统·现代c++
2501_914245931 小时前
C语言设计模式详解:从理论到实践的完整指南
c语言·开发语言·设计模式
米罗篮4 小时前
矩阵快速幂 (Exponentiation By Squaring Applied To Matrices)
c++·线性代数·算法·矩阵
肖爱Kun4 小时前
C++设计策略模式
开发语言·c++·策略模式
炸膛坦客5 小时前
单片机/C/C++八股:(二十四)编译文件( .bin 和 .hex ,包括 .elf 和 .axf )
c语言·c++·单片机
CaffeinePro5 小时前
四⼤极简架构原则KISS/DRY/YAGNI/LOD
设计模式·架构
cpp_25016 小时前
P10098 [ROIR 2023] 地铁建设 (Day 2)
数据结构·c++·算法·贪心·二分答案·洛谷题解
霸道流氓气质6 小时前
SpringBoot中设计模式组合使用示例-策略、模板、观察者、门面、工厂、单例。
spring boot·后端·设计模式