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

设计模式之访问者模式

目录

  • 定义
  • 结构
  • 适用场景
  • 使用示例

定义

       访问者模式(Visitor Pattern)是一种‌行为型设计模式‌,其核心思想是将数据结构与数据操作解耦,允许在不修改现有对象结构的前提下定义作用于对象元素的新操作。
       访问者模式有以下核心要点:
       1)‌数据结构稳定,被访问的对象结构(元素类)相对固定,不频繁变动。
       2)‌操作可扩展,新增操作只需添加新的访问者类,无需修改元素类代码,符合开闭原则。
       3)‌双分派机制,通过accept(Visitor)和visit(Element)的两次动态绑定,根据元素类型调用对应操作。

结构

在这里插入图片描述

适用场景

       访问者模式适用于以下场景:
       1)‌对象结构稳定但需频繁新增操作,如编译器语法树分析(类型检查、代码优化等操作)。
       2)‌避免元素类被污染,当元素类不宜直接包含某些操作时(如电商商品类不宜包含打折、导出等业务逻辑)。
       3)‌统一处理复合结构,对集合、树形结构中的异构元素执行统一操作(如文档导出、统计计算)。

使用示例

       电商订单价格计算。假设订单包含不同类型商品(普通商品/折扣商品),需支持多种计算规则(含税价计算、满减计算)。
       定义抽象Element

/*** 定义商品元素接口(抽象Element角色)*/
public interface OrderItem {void accept(PriceVisitor visitor);double getBasePrice(); // 所有商品必须提供基础价格}

       定义具体Element

/*** 具体商品类(普通商品)*/
public class RegularItem implements OrderItem {private String name;private double price;public RegularItem(String name, double price) {this.name = name;this.price = price;}@Overridepublic void accept(PriceVisitor visitor) {visitor.visit(this); // 关键:将自身作为参数传递}@Overridepublic double getBasePrice() {return price;}// 普通商品特有方法public String getName() {return name;}}/*** 具体商品类(折扣商品)*/
public class DiscountItem implements OrderItem {private String name;private double price;private double discountRate; // 折扣率public DiscountItem(String name, double price, double discountRate) {this.name = name;this.price = price;this.discountRate = discountRate;}@Overridepublic void accept(PriceVisitor visitor) {visitor.visit(this); // 关键:将自身作为参数传递}@Overridepublic double getBasePrice() {return price * discountRate;}// 折扣商品特有方法public double getDiscountRate() {return discountRate;}public String getName() {return name;}
}

       定义抽象Visitor

/*** 访问者接口(抽象Visitor角色)*/
public interface PriceVisitor {void visit(RegularItem item);void visit(DiscountItem item);}

       定义具体Visitor

/*** 具体访问者:满减计算*/
public class PromotionVisitor implements PriceVisitor {private final double threshold; // 满减阈值private final double reduction; // 减免金额public PromotionVisitor(double threshold, double reduction) {this.threshold = threshold;this.reduction = reduction;}@Overridepublic void visit(RegularItem item) {double finalPrice = item.getBasePrice();if (finalPrice >= threshold) {finalPrice -= reduction;System.out.printf("普通商品[%s] 满减后价格: %.2f\n",item.getName(), finalPrice);}}@Overridepublic void visit(DiscountItem item) {// 折扣商品不参与满减System.out.println("折扣商品[" + item.getName() + "]不参与满减活动");}}/*** 具体访问者:含税价格计算*/
public class TaxPriceVisitor implements PriceVisitor {private double totalTax = 0;private final double taxRate;public TaxPriceVisitor(double taxRate) {this.taxRate = taxRate;}@Overridepublic void visit(RegularItem item) {double tax = item.getBasePrice() * taxRate;totalTax += tax;System.out.printf("普通商品[%s] 含税价: %.2f (税额: %.2f)\n",item.getName(), item.getBasePrice() + tax, tax);}@Overridepublic void visit(DiscountItem item) {double tax = item.getBasePrice() * taxRate * 0.5; // 折扣商品税额减半totalTax += tax;System.out.printf("折扣商品[%s]含税价: %.2f (折扣率: %.1f, 税额: %.2f)\n",item.getName(),item.getBasePrice() + tax, item.getDiscountRate(), tax);}public double getTotalTax() {return totalTax;}}

       定义ObjectStructure角色

/*** 对象结构(订单)(ObjectStructure角色)*/
public class Order {private List<OrderItem> items = new ArrayList<>();public void addItem(OrderItem item) {items.add(item);}public void accept(PriceVisitor visitor) {for (OrderItem item : items) {item.accept(visitor); // 触发双分派}}
}

       测试

public class Client {public static void main(String[] args) {Order order = new Order();order.addItem(new RegularItem("iPhone", 5999));order.addItem(new DiscountItem("运动鞋", 399, 0.8));// 计算含税价TaxPriceVisitor taxVisitor = new TaxPriceVisitor(0.13);order.accept(taxVisitor);System.out.println("总税额: " + taxVisitor.getTotalTax());// 计算满减PromotionVisitor promoVisitor = new PromotionVisitor(5000, 300);order.accept(promoVisitor);}
}
http://www.xdnf.cn/news/15009.html

相关文章:

  • 使用Langchain访问个人数据
  • SpringBoot系列—入门
  • PostgreSQL表操作
  • 深度学习5(深层神经网络 + 参数和超参数)
  • C++ 网络编程(15) 利用asio协程搭建异步服务器
  • 从数据洞察到设计创新:UI前端如何利用数字孪生提升用户体验?
  • 浏览器与服务器的交互
  • dify 1.5.1版本全面解析——知识库索引、动态参数及结构化输出插件全新登场
  • STM32的 syscalls.c 和 sysmem.c
  • 《C++初阶之类和对象》【经典案例:日期类】
  • RESTful API 安装使用教程
  • 黑马python(二十五)
  • Spring Boot + 本地部署大模型实现:优化与性能提升
  • 基于Linux的Spark本地模式环境搭建实验指南
  • 【github】想fork的项目变为私有副本
  • 项目介绍:LangGPT
  • Android View的绘制原理详解
  • 使用reactor-rabbitmq库监听Rabbitmq
  • Python 量化交易安装使用教程
  • opencv的颜色通道问题 rgb bgr
  • 如何查看自己电脑的CUDA版本?
  • 【深度解析】Seedance 1.0:重新定义 AI 视频生成的工业级标准
  • 《Java修仙传:从凡胎到码帝》第三章:缩进之劫与函数峰试炼
  • python脚本编程:使用BeautifulSoup爬虫库获取热门单机游戏排行榜
  • PHP从字符串到数值的类型转换
  • 三、jenkins使用tomcat部署项目
  • 服务器间接口安全问题的全面分析
  • 模拟热血三国内城安置建筑物
  • 【wps】 excel 删除重复项
  • 【Spring Boot】HikariCP 连接池 YAML 配置详解