访问者模式

举报
Further_Step 发表于 2024/12/12 16:59:36 2024/12/12
【摘要】 喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞! 访问者模式详解 概念访问者模式(Visitor Pattern)是一种行为型设计模式,用于将数据结构与其操作解耦。通过在不改变数据结构的前提下,增加新的操作,访问者模式提供了一种灵活的方式来实现功能扩展。 关键特性分离操作:将具体操作从对象本身分离,使得操作逻辑集中在访问者中。支持扩展:容易增加新的操作,但增加新的数据结...

喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞

访问者模式详解

概念

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

关键特性

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

适用场景

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

使用案例

1. 编译器中的语法树

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

2. 文件系统

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

3. 游戏场景

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

优缺点

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

类图

«interface»Visitor+visitConcreteElementA(ConcreteElementA element)+visitConcreteElementB(ConcreteElementB element)ConcreteVisitor1+visitConcreteElementA(ConcreteElementA element)+visitConcreteElementB(ConcreteElementB element)ConcreteVisitor2+visitConcreteElementA(ConcreteElementA element)+visitConcreteElementB(ConcreteElementB element)«abstract»Element+accept(Visitor visitor)ConcreteElementA+accept(Visitor visitor)+operationA()ConcreteElementB+accept(Visitor visitor)+operationB()ObjectStructure+addElement(Element element)+accept(Visitor visitor)visitvisitvisitvisit

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);
    }
}

欢迎关注、点赞、收藏!更多系列内容可以点击专栏目录订阅,感谢支持,再次祝大家祉猷并茂,顺遂无虞
在这里插入图片描述

若将文章用作它处,请一定注明出处,商用请私信联系我!

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。