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

104、23种设计模式之访问者模式(13/23)

一、定义

访问者模式是一种行为型设计模式,其核心思想是将数据结构与数据操作解耦。通过定义独立的访问者对象,它允许在不修改现有元素类结构的前提下,为元素添加新的操作。该模式基于双重分派机制(对象结构接受访问者 + 元素调用访问者的具体方法),实现动态行为扩展。

二、应用场景

1.复杂数据结构需多种操作

  • 场景:编译器抽象语法树(AST)需执行语法检查、语义分析、代码生成等操作。

  • 解决方案:为每个操作定义独立访问者(如TypeCheckerVisitor、CodeGeneratorVisitor),避免修改节点类。

2.对象结构稳定但操作频繁变化

  • 场景:电商系统中商品类型固定(手机、电脑),但需支持打折、加入购物车、生成小票等操作。
  • 解决方案:通过ShoppingCartVisitor实现不同计算逻辑,元素类仅需实现accept()方法。

3.集中管理相似行为

  • 场景:文档处理需支持导出PDF、生成目录等操作。
  • 解决方案:访问者模式将导出逻辑聚合在访问者中,避免元素类臃肿。

4.跨层次结构访问

  • 场景:图形编辑器中圆形、矩形需支持渲染、导出、计算面积等操作。
  • 解决方案:访问者模式统一处理异构对象,避免元素类污染。

5.动态权限控制

  • 场景:用户和角色结构稳定,但权限校验逻辑(如RBAC模型)需动态扩展。
  • 解决方案:通过访问者实现非侵入式权限计算。

三、优缺点

1.优点

  • 扩展性强:新增操作仅需添加访问者类,符合开闭原则。
  • 职责分离:数据结构与操作逻辑解耦,提升可维护性。
  • 集中化操作:相似行为聚合在访问者中(如报表生成)。

2.缺点

  • 元素类扩展困难:新增元素需修改所有访问者接口。
  • 破坏封装性:访问者需了解元素内部状态,可能暴露敏感数据。
  • 对象结构变化导致访问者修改:元素关系变化会引发级联修改。

四、C# 示例代码

using System;
using System.Collections.Generic;// 抽象元素接口
public interface IElement {void Accept(IVisitor visitor);
}// 具体元素类
public class Book : IElement {public string Title { get; set; }public double Price { get; set; }public Book(string title, double price) {Title = title;Price = price;}public void Accept(IVisitor visitor) {visitor.Visit(this);}
}public class Fruit : IElement {public string Name { get; set; }public double Weight { get; set; }public Fruit(string name, double weight) {Name = name;Weight = weight;}public void Accept(IVisitor visitor) {visitor.Visit(this);}
}// 抽象访问者接口
public interface IVisitor {void Visit(Book book);void Visit(Fruit fruit);
}// 具体访问者类:打折计算
public class DiscountVisitor : IVisitor {public void Visit(Book book) {Console.WriteLine($"书籍《{book.Title}》打折后价格:{book.Price * 0.9:C}");}public void Visit(Fruit fruit) {Console.WriteLine($"{fruit.Name}{fruit.Weight}kg)不打折");}
}// 对象结构:管理元素集合
public class ObjectStructure {private List<IElement> elements = new List<IElement>();public void AddElement(IElement element) {elements.Add(element);}public void Accept(IVisitor visitor) {foreach (var element in elements) {element.Accept(visitor);}}
}// 客户端代码
class Program {static void Main(string[] args) {ObjectStructure structure = new ObjectStructure();structure.AddElement(new Book("C# Design Patterns", 59.99));structure.AddElement(new Fruit("Apple", 1.5));IVisitor discountVisitor = new DiscountVisitor();structure.Accept(discountVisitor);}
}

五、关键点总结

1.双重分派机制:

  • 元素结构调用Accept()方法,将自身传递给访问者。
  • 元素调用访问者的Visit()方法,实现动态绑定。

2.适用条件:

  • 对象结构稳定(元素类型不频繁变化)。
  • 需要频繁新增操作(如编译器AST处理)。

3.设计原则:

  • 开闭原则:对扩展开放,对修改关闭。
  • 单一职责原则:访问者集中管理相关行为。

4.替代方案:

  • 若元素类型频繁变化,可考虑策略模式或组合模式。
  • 若操作简单,直接内联方法可能更高效。

六、典型应用案例

  • 编译器设计:遍历AST执行语义分析、代码生成。
  • 电商系统:商品打折、生成小票等操作解耦。
  • 图形编辑器:统一处理不同图形的渲染和导出。
  • 金融计算:风险评估、收益计算等算法扩展。

在这里插入图片描述

http://www.dtcms.com/a/394715.html

相关文章:

  • 什么是Mvcc
  • 如何在同一站点支持多版本的 reCAPTCHA 的兼容性方案
  • 管家预约字段修复说明
  • java面试day3 | 框架篇、Spring、SpringMVC、SpringBoot、MyBatis、注解、AOP、Bean
  • 【log4j2】log4j2插件挂载变更msg格式(工作实战,原理详解)
  • MVCC(多版本并发控制):InnoDB 高并发的核心技术
  • 决策树习题
  • PHP-ThinkPhp漏洞学习-MVC模型路由访问模版渲染安全写法版本漏洞(2024小迪安全Day31)
  • [已修复] iTunes 无法识别您的 iPhone
  • EC2 实例的操作系统 (OS) 未能成功从 AWS 的网络服务 (DHCP) 中获取到分配给它的私有 IPv4 地址
  • Vercel、Netlify、AWS 与 Cloudflare:前端部署与边缘计算平台全景对比
  • 【Threejs】【工具类】Raycaster实现 3D 交互(如鼠标拾取、碰撞检测)的核心工具
  • Fay数字人QA功能详解
  • NETSTAT命令详解
  • FFmpeg 5.x 编译 so 文件的记录
  • 以开启https的nginx转发流量到minio
  • StarRocks 各类索引以及存储位置详解
  • PromptPilot 技术深解,工程化提示词开发如何让大模型准确率大大提高
  • RTX4090:AI与深度学习应用实践的革命性推动者
  • Cursor Multi-Root Workspace 新特性深度实战:一次打开 React 前端 + Go 后端,AI 自动跨项目跳转、联调、写代码!
  • 如何处理单位换算的问题
  • Docker部署 MySQL+Mycat
  • RTX4090:极致性能探索与硬核评测
  • DM物理存储结构及内存结构
  • ASP.NET Core MVC 路由逻辑初探
  • 【Python办公】文字转视频(可自定义颜色、字体大小)
  • 数据洪流时代,如何挑选一款面向未来的时序数据库?IoTDB 的答案
  • python+django/flask的吉安红色旅游平台 红色教育景区展示+图文资讯发布+评论互动功能系统java+nodejs
  • 设计模式(C++)详解——代理模式 (Proxy Pattern)(2)
  • 详解 Kubernetes 命令:kubectl exec -it nginx -- bash 及实战场景