访问者模式

简介: 访问者模式是一种行为型设计模式,用于将数据结构与其操作解耦。通过在不改变数据结构的前提下增加新的操作,访问者模式提供了一种灵活的方式来实现功能扩展。其关键特性包括分离操作、支持扩展和双分派机制。适用于需要对对象结构中的元素执行多种操作、频繁扩展操作以及不希望操作逻辑和数据结构耦合的场景。常见的使用案例包括编译器中的语法树、文件系统和游戏场景。优点是增加操作时无需修改数据结构,符合开闭原则;缺点是添加新的数据结构类型时需要修改所有访问者类,维护成本较高。

访问者模式详解

概念

访问者模式(Visitor Pattern)是一种行为型设计模式,用于将数据结构与其操作解耦。通过在不改变数据结构的前提下,增加新的操作,访问者模式提供了一种灵活的方式来实现功能扩展。

关键特性

  • 分离操作:将具体操作从对象本身分离,使得操作逻辑集中在访问者中。
  • 支持扩展:容易增加新的操作,但增加新的数据结构时会比较复杂。
  • 双分派机制:通过在访问者和元素之间的双向调用实现。

适用场景

  • 需要对对象结构中的元素执行多种操作:每种操作需要在对象类型之间有区别。
  • 需要频繁扩展操作:在已有的对象结构中增加新功能时无需修改数据结构。
  • 不希望操作逻辑和数据结构耦合:将操作集中在访问者中,数据结构更清晰。

使用案例

1. 编译器中的语法树

  • 场景:对语法树中的不同节点(如函数、变量)进行语义检查、代码生成等操作。
  • 解决:语法树节点实现Element接口,不同的操作通过访问者完成。

2. 文件系统

  • 场景:对文件和目录执行操作,如统计大小、权限检查等。
  • 解决:文件和目录实现Element接口,具体操作用访问者实现。

3. 游戏场景

  • 场景:在游戏中,为不同类型的单位(如士兵、坦克)计算攻击力、升级逻辑。
  • 解决:单位类实现Element接口,计算攻击力或升级功能使用访问者完成。

优缺点

优点 缺点
增加操作时无须修改数据结构,符合开闭原则 添加新的数据结构类型需要修改所有访问者类,维护成本高
使得操作集中,便于管理和维护 数据结构与访问者模式之间存在依赖
支持双分派,允许根据运行时类型执行操作 对数据结构的要求较高,必须稳定不变

类图

export (14).png


C++实现

#include <iostream>
#include <vector>
#include <memory>

class ConcreteElementA;
class ConcreteElementB;

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

// 元素接口
class Element {
public:
   virtual ~Element() = default;
   virtual void Accept(Visitor* visitor) = 0;
};

// 具体元素A
class ConcreteElementA : public Element {
public:
   void OperationA() {
       std::cout << "ConcreteElementA OperationA\n";
   }
   void Accept(Visitor* visitor) override {
       visitor->Visit(this);
   }
};

// 具体元素B
class ConcreteElementB : public Element {
public:
   void OperationB() {
       std::cout << "ConcreteElementB OperationB\n";
   }
   void Accept(Visitor* visitor) override {
       visitor->Visit(this);
   }
};

// 具体访问者
class ConcreteVisitor : public Visitor {
public:
   void Visit(ConcreteElementA* element) override {
       std::cout << "Visiting ConcreteElementA\n";
       element->OperationA();
   }
   void Visit(ConcreteElementB* element) override {
       std::cout << "Visiting ConcreteElementB\n";
       element->OperationB();
   }
};

// 对象结构
class ObjectStructure {
private:
   std::vector<std::unique_ptr<Element>> elements;

public:
   void AddElement(std::unique_ptr<Element> element) {
       elements.push_back(std::move(element));
   }
   void Accept(Visitor* visitor) {
       for (const auto& element : elements) {
           element->Accept(visitor);
       }
   }
};

// 示例用法
int main() {
   ObjectStructure structure;
   structure.AddElement(std::make_unique<ConcreteElementA>());
   structure.AddElement(std::make_unique<ConcreteElementB>());

   ConcreteVisitor visitor;
   structure.Accept(&visitor);

   return 0;
}


C#实现

using System;
using System.Collections.Generic;

// Visitor Interface
public interface IVisitor {
   void Visit(ConcreteElementA element);
   void Visit(ConcreteElementB element);
}

// Element Interface
public abstract class Element {
   public abstract void Accept(IVisitor visitor);
}

// Concrete Element A
public class ConcreteElementA : Element {
   public override void Accept(IVisitor visitor) {
       visitor.Visit(this);
   }

   public void OperationA() {
       Console.WriteLine("ConcreteElementA OperationA");
   }
}

// Concrete Element B
public class ConcreteElementB : Element {
   public override void Accept(IVisitor visitor) {
       visitor.Visit(this);
   }

   public void OperationB() {
       Console.WriteLine("ConcreteElementB OperationB");
   }
}

// Concrete Visitor
public class ConcreteVisitor : IVisitor {
   public void Visit(ConcreteElementA element) {
       Console.WriteLine("Visiting ConcreteElementA");
       element.OperationA();
   }

   public void Visit(ConcreteElementB element) {
       Console.WriteLine("Visiting ConcreteElementB");
       element.OperationB();
   }
}

// Object Structure
public class ObjectStructure {
   private readonly List<Element> _elements = new List<Element>();

   public void AddElement(Element element) {
       _elements.Add(element);
   }

   public void Accept(IVisitor visitor) {
       foreach (var element in _elements) {
           element.Accept(visitor);
       }
   }
}

// Example Usage
class Program {
   static void Main(string[] args) {
       var structure = new ObjectStructure();
       structure.AddElement(new ConcreteElementA());
       structure.AddElement(new ConcreteElementB());

       var visitor = new ConcreteVisitor();
       structure.Accept(visitor);
   }
}

目录
相关文章
|
4月前
|
设计模式 Java
访问者模式问题之在不使用访问者模式的情况下,怎么在一个 SelectNode 类中实现 extractFunctions 方法
访问者模式问题之在不使用访问者模式的情况下,怎么在一个 SelectNode 类中实现 extractFunctions 方法
|
7月前
|
算法
行为型 访问者模式
行为型 访问者模式
63 0
|
设计模式 算法 BI
设计模式~访问者模式(Visitor)-15
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对
49 0
|
设计模式 Java 关系型数据库
访问者模式解读
访问者模式解读
今天说说你不知道的访问者模式
今天说说你不知道的访问者模式
80 0
|
设计模式 算法 Java
Java设计模式-访问者模式(Visitor)
Java设计模式-访问者模式(Visitor)
|
设计模式 程序员
访问者模式是啥?咋实现呀?
访问者模式是啥?咋实现呀?
|
设计模式
我学会了,访问者模式
访问者模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
120 0
我学会了,访问者模式
|
设计模式 算法 Java
观察者模式和访问者模式(2)
观察者模式和访问者模式(2)
172 0
观察者模式和访问者模式(2)

热门文章

最新文章