当前位置: 首页 > article >正文

设计模式 23 访问者模式

设计模式 23

  • 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
  • 结构型模式(7):适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式
  • 行为型模式(11):责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式

文章目录

  • 设计模式 23
    • 访问者模式(Visitor Pattern)
      • 1 定义
      • 2 结构
      • 3 示例代码
      • 4 特点
      • 5 适用场景
      • 6 总结

访问者模式(Visitor Pattern)

1 定义

访问者模式通过引入一个访问者接口,使得你可以在元素类中接受访问者,并让访问者决定对元素的具体操作。访问者模式的关键在于分离算法和数据结构,使得新的操作可以轻松地添加而不影响已有的数据结构。

2 结构

访问者模式包含以下角色:

  • 访问者接口(Visitor): 为每种元素类型定义一个访问方法。访问者接口通常提供一个Visit方法,针对不同的元素类有不同的实现。
  • 具体访问者(ConcreteVisitor): 实现访问者接口的具体操作,对元素执行具体的操作。
  • 元素接口(Element): 声明一个Accept方法,该方法接受访问者对象并调用访问者的Visit方法。
  • 具体元素(ConcreteElement): 实现元素接口,定义元素的具体行为,并在Accept方法中调用访问者的对应方法。
  • 对象结构(ObjectStructure): 通常是一个包含多个不同类型元素的集合,它可以遍历这些元素并让访问者访问它们。

UML 类图

+---------------------------+         +---------------------------+
|      Visitor              | <------ |     Element               |
+---------------------------+         +---------------------------+
| + VisitElementA():void    |         | + Accept(v:Visitor): void |
| + VisitElementB():void    |         +---------------------------+
+---------------------------+               ^
        ^                                   |
        |                                   |
+---------------------------+         +---------------------------+
| ConcreteVisitor           |         | ConcreteElement           |
+---------------------------+         +---------------------------+
| + VisitElementA():void    |         | + Accept(v:Visitor): void |
| + VisitElementB():void    |         | + OperationA(): void      |
+---------------------------+         +---------------------------+

3 示例代码

假设我们要实现一个报表系统,系统中包含不同类型的员工(如工程师和经理),每种员工有不同的报表要求。我们可以使用访问者模式来实现报表的生成,使得报表的生成与员工类型的实现分离。

访问者接口

// 访问者接口
public interface IVisitor
{
    void Visit(Engineer engineer);
    void Visit(Manager manager);
}

具体访问者

// 具体访问者 - 报表生成器
public class ReportGenerator : IVisitor
{
    public void Visit(Engineer engineer)
    {
        Console.WriteLine($"Generating report for Engineer: {engineer.Name}");
    }

    public void Visit(Manager manager)
    {
        Console.WriteLine($"Generating report for Manager: {manager.Name} with {manager.SubordinatesCount} subordinates.");
    }
}

元素接口

// 元素接口
public interface IEmployee
{
    void Accept(IVisitor visitor);
}

具体元素类

// 具体元素 - 工程师
public class Engineer : IEmployee
{
    public string Name { get; private set; }

    public Engineer(string name)
    {
        Name = name;
    }

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}

// 具体元素 - 经理
public class Manager : IEmployee
{
    public string Name { get; private set; }
    public int SubordinatesCount { get; private set; }

    public Manager(string name, int subordinatesCount)
    {
        Name = name;
        SubordinatesCount = subordinatesCount;
    }

    public void Accept(IVisitor visitor)
    {
        visitor.Visit(this);
    }
}

对象结构

// 对象结构 - 员工列表
public class EmployeeStructure
{
    private List<IEmployee> _employees = new List<IEmployee>();

    public void Attach(IEmployee employee)
    {
        _employees.Add(employee);
    }

    public void Detach(IEmployee employee)
    {
        _employees.Remove(employee);
    }

    public void Accept(IVisitor visitor)
    {
        foreach (var employee in _employees)
        {
            employee.Accept(visitor);
        }
    }
}

客户端代码

class Program
{
    static void Main(string[] args)
    {
        // 创建员工结构
        EmployeeStructure employeeStructure = new EmployeeStructure();

        // 添加员工
        employeeStructure.Attach(new Engineer("John"));
        employeeStructure.Attach(new Manager("Alice", 5));

        // 创建报表生成器
        ReportGenerator reportGenerator = new ReportGenerator();

        // 生成报表
        employeeStructure.Accept(reportGenerator);
    }
}

运行结果

Generating report for Engineer: John
Generating report for Manager: Alice with 5 subordinates.

在这个例子中,IVisitor 定义了对不同员工类型(EngineerManager)的访问方法。ReportGenerator 是具体的访问者,实现了生成报表的逻辑。IEmployee 接口定义了 Accept 方法,EngineerManager 作为具体的元素,实现了接受访问者的逻辑。EmployeeStructure 作为对象结构,管理了所有的员工,并允许访问者访问这些员工。

4 特点

  • 优点:

    • 增加新的操作容易: 可以在不修改元素类的情况下,通过添加新的访问者类来增加新的操作。

    • 将操作与对象结构分离: 访问者模式将数据结构和操作分离,使得数据结构和操作各自独立,符合单一职责原则。

    • 扩展性好: 可以很容易地增加新的访问者来实现新的功能。

  • 缺点:

    • 增加元素类的复杂性: 每个元素类都必须实现接受访问者的方法,这可能会增加类的复杂性。

    • 违反开闭原则: 如果需要修改元素的结构或添加新的元素类型,则需要修改所有的访问者类,这与开闭原则相违背。

    • 双分派: 访问者模式要求进行双分派,即根据元素类型和访问者类型分别调用相应的方法,这可能会导致系统的复杂性增加。

5 适用场景

  • 对象结构稳定: 当对象结构相对稳定,但操作经常变化时,使用访问者模式可以有效地管理这些变化。
  • 需要对对象结构中的对象进行复杂操作: 访问者模式适用于对对象结构中的元素进行复杂操作,且这些操作可能会频繁变化的场景。
  • 对象结构中包含多个不相关的类: 当对象结构中包含多个不相关的类,需要对这些类执行某些操作时,访问者模式可以通过统一的访问者接口来处理这些操作。

6 总结

访问者模式通过将操作分离到独立的访问者对象中,使得在不修改元素类的情况下,可以增加新的操作。它适用于对象结构稳定但操作经常变化的场景。然而,由于需要对每个元素类增加接受访问者的方法,并且可能导致违反开闭原则,因此在使用时需要权衡利弊。在需要对复杂对象结构进行扩展和管理时,访问者模式是一种强大的设计模式。


http://www.kler.cn/a/306713.html

相关文章:

  • 客户案例 | 如何利用Ansys工具提供互联系统(以及系统的系统),从而使“软件定义汽车”成为可能
  • DAY6 线程
  • HarmonyOS ArkTS 下拉列表组件
  • [Docker#4] 镜像仓库 | 部分常用命令
  • 为什么数学常数在 powershell 中以不同的方式截断?
  • FastDDS服务发现之EDP的收发
  • Wophp靶场寻找漏洞练习
  • 从OracleCloudWorld和财报看Oracle的转变
  • 苏州科技大学、和数联合获得国家知识产权局颁发的3项发明专利证书
  • 计算机毕业设计 在线新闻聚合平台的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • C++复习day12
  • Android桌面(Launcher)源码分析
  • 【LeetCode每日一题】2024年9月第二周(下)
  • 【C++】学完c语言后的c++基础知识补充!(命名空间、输入和输出、缺省函数、函数重载、引用、内联函数代替宏、nullptr代替NULL)
  • SpringBoot Kafka发送消息与接收消息实例
  • Nignx 增加权限(windows)
  • BrainSegFounder:迈向用于神经影像分割的3D基础模型|文献速递--Transformer架构在医学影像分析中的应用
  • 系统架构设计师 需求分析篇一
  • Oracle临时表
  • 类型转换等 面试真题
  • Vue常见面试题目
  • 横向移动-WMI
  • k8s--pod控制器--1
  • Qt:饿汉单例(附带单例使用和内存管理)
  • Redis 的数据持久化
  • Ajax 使用流程详解