访问者模式

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

访问者模式详解

概念

访问者模式(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);
   }
}

目录
相关文章
|
3月前
|
设计模式 缓存 算法
Java设计模式-访问者模式(22)
Java设计模式-访问者模式(22)
|
7月前
|
设计模式 Java 容器
聊聊Java设计模式-访问者模式
访问者模式(Visitor Pattern)指将作用域某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作。
65 3
聊聊Java设计模式-访问者模式
|
7月前
|
算法
行为型 访问者模式
行为型 访问者模式
61 0
|
7月前
|
设计模式 uml C++
行为型 迭代器模式
行为型 迭代器模式
45 0
|
设计模式 Java uml
|
设计模式 Java 关系型数据库
访问者模式解读
访问者模式解读
今天说说你不知道的访问者模式
今天说说你不知道的访问者模式
80 0
|
设计模式 程序员
访问者模式是啥?咋实现呀?
访问者模式是啥?咋实现呀?
|
设计模式 XML Java
java设计模式之访问者模式
写这篇文章之前,我也看了十几篇网络大牛写的访问者设计模式的文章,都说这个访问者模式是最复杂的一个,但是我觉得跟其他的设计模式并没有太多的不同,因此自己整理了一下,相信大多数人都能看懂。
188 0
java设计模式之访问者模式