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

【设计模式】访问者模式

**简介
假设你有一个购物车(对象结构),里面有多种商品(元素),如苹果、牛奶、书籍。每个商品的计价规则不同:

  • 水果按重量计价
  • 牛奶按数量计价
  • 书籍按固定价格计价
    现在需要实现两种功能:
  1. 计算总价
  2. 打印购物小票

访问者模式的作用

  • 将商品和操作(如计算价格、打印小票)分离。
  • 新增功能(如打折计算)时,只需新增一个“访问者”,无需修改商品类。

适用场景

  • 对象结构稳定,但需要频繁新增操作。
  • 需要对同一对象结构进行多种独立操作(如计算总价、导出数据)。

优点

  • 符合开闭原则:新增操作无需修改对象结构。
  • 操作逻辑集中:每个访问者类负责一个独立功能。

缺点

  • 对象结构变化时,所有访问者类都需要修改。
  • 过度使用会导致代码复杂度增加。

代码

// 元素接口:商品
interface ItemElement {int accept(ShoppingCartVisitor visitor);
}// 具体元素:书籍
class Book implements ItemElement {private int price;private String isbn;public Book(int price, String isbn) {this.price = price;this.isbn = isbn;}public int accept(ShoppingCartVisitor visitor) {return visitor.visit(this);}public int getPrice() { return price; }
}// 具体元素:水果
class Fruit implements ItemElement {private int pricePerKg;private int weight;public Fruit(int pricePerKg, int weight) {this.pricePerKg = pricePerKg;this.weight = weight;}public int accept(ShoppingCartVisitor visitor) {return visitor.visit(this);}public int getPricePerKg() { return pricePerKg; }public int getWeight() { return weight; }
}// 访问者接口
interface ShoppingCartVisitor {int visit(Book book);int visit(Fruit fruit);
}// 具体访问者:计算总价
class ShoppingCartVisitorImpl implements ShoppingCartVisitor {public int visit(Book book) {return book.getPrice();}public int visit(Fruit fruit) {return fruit.getPricePerKg() * fruit.getWeight();}
}// 客户端代码
public class Client {public static void main(String[] args) {ItemElement[] items = new ItemElement[]{new Book(100, "ISBN-123"),new Fruit(10, 2)};ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();int total = 0;for (ItemElement item : items) {total += item.accept(visitor);}System.out.println("Total cost: " + total); // 输出 120}
}

类图
在这里插入图片描述

@startuml
interface ItemElement {+ accept(ShoppingCartVisitor visitor): int
}class Book {- price: int- isbn: String+ accept(ShoppingCartVisitor visitor): int
}class Fruit {- pricePerKg: int- weight: int+ accept(ShoppingCartVisitor visitor): int
}interface ShoppingCartVisitor {+ visit(Book book): int+ visit(Fruit fruit): int
}class ShoppingCartVisitorImpl {+ visit(Book book): int+ visit(Fruit fruit): int
}ItemElement <|-- Book
ItemElement <|-- Fruit
ShoppingCartVisitor <|-- ShoppingCartVisitorImpl
Book --> ShoppingCartVisitor
Fruit --> ShoppingCartVisitor
@enduml

4. 实际应用场景案例:编译器语法树分析

场景:编译器需要遍历抽象语法树(AST),进行类型检查、代码生成等操作。

// 表达式元素接口
interface Expr {<T> T accept(Visitor<T> visitor);
}// 具体元素:数字表达式
class Number implements Expr {private int value;public Number(int value) { this.value = value; }public <T> T accept(Visitor<T> visitor) {return visitor.visit(this);}public int getValue() { return value; }
}// 具体元素:加法表达式
class Addition implements Expr {private Expr left;private Expr right;public Addition(Expr left, Expr right) {this.left = left;this.right = right;}public <T> T accept(Visitor<T> visitor) {return visitor.visit(this);}public Expr getLeft() { return left; }public Expr getRight() { return right; }
}// 访问者接口
interface Visitor<T> {T visit(Number number);T visit(Addition addition);
}// 具体访问者:表达式求值
class EvaluateVisitor implements Visitor<Integer> {public Integer visit(Number number) {return number.getValue();}public Integer visit(Addition addition) {return addition.getLeft().accept(this) + addition.getRight().accept(this);}
}// 客户端代码
public class CompilerClient {public static void main(String[] args) {Expr expr = new Addition(new Number(10),new Addition(new Number(20), new Number(30)));EvaluateVisitor evaluator = new EvaluateVisitor();int result = expr.accept(evaluator);System.out.println("Result: " + result); // 输出 60}
}

相关文章:

【设计模式】访问者模式

**简介 假设你有一个购物车&#xff08;对象结构&#xff09;&#xff0c;里面有多种商品&#xff08;元素&#xff09;&#xff0c;如苹果、牛奶、书籍。每个商品的计价规则不同&#xff1a; 水果按重量计价牛奶按数量计价书籍按固定价格计价 现在需要实现两种功能&#xff1…...

【ISP】ISP pipeline(AI)

ISP Pipeline 全流程概览 ISP&#xff08;Image Signal Processing&#xff0c;图像信号处理&#xff09;流程通常从原始 Bayer 数据出发&#xff0c;经过一系列模块处理&#xff0c;逐步完成图像校正和增强&#xff0c;最终生成用于显示或编码的标准图像。常见处理模块包括&a…...

【设计模式】模板模式

简介 假设你要冲泡咖啡和茶&#xff0c;两者的流程相似但部分步骤不同&#xff1a; 烧水&#xff08;公共步骤&#xff09;加入主材料&#xff08;咖啡粉/茶叶&#xff09;添加调料&#xff08;糖/牛奶&#xff09;→ 可选步骤倒进杯子&#xff08;公共步骤&#xff09; 模板…...

GDB调试程序的基本命令和用法(Qt程序为例)

1. 引言 GDB&#xff08;GNU Debugger&#xff09;是一个强大的命令行调试工具&#xff0c;它可以帮助开发者在程序运行时查找和修复错误。当调试Qt程序时&#xff0c;GDB同样适用&#xff0c;并且能够帮助开发者定位诸如数组越界挂死等复杂问题。 2. 基本命令 2.1 启动GDB …...

vue3腾讯云直播 前端推流

1、在index.html文件中引入&#xff08;在body体中&#xff09; <script src"https://video.sdk.qcloudecdn.com/web/TXLivePusher-2.1.1.min.js" charset"utf-8"></script> 2、vue文件中&#xff0c;添加video推流&#xff08;我用的推流地…...

DP_AUX辅助通道介绍

DisplayPort&#xff08;简称DP&#xff09;是一个由PC及芯片制造商联盟开发&#xff0c;视频电子标准协会&#xff08;VESA&#xff09;标准化的数字式视频接口标准。该接口免认证、免授权金&#xff0c;主要用于视频源与显示器等设备的连接&#xff0c;并也支持携带音频、USB…...

【微机及接口技术】- 第九章 串行通信与串行接口(下)

文章目录 第二节 串行通信协议一、异步串行通信协议二、同步串行通信协议 第三节 串行接口标准RS-232C一、RS-232C信号线定义二、电气特性 第四节 可编程串行接口芯片8251A一、基本性能二、内部结构三、外部引脚功能1. 同CPU的连接信号2. MODEM控制信号&#xff08;4个&#xf…...

人形机器人制造—3D打印推动微型化与轻量化设计

在人形机器人仿生架构的构建中&#xff0c;多模态传感器集群与仿生关节矩阵的拓扑融合&#xff0c;正催生第三代具身智能的力学革命。通过分布式触觉薄膜、双目视觉惯性测量单元&#xff08;200Hz采样率&#xff09;与肌电模拟传感器的三重耦合&#xff0c;机器人获得了超越人类…...

前端性能优化高频面试题解析与实战指南(2025版)

一、前端性能优化核心面试题汇总 1. 浏览器加载优化相关问题 Q1&#xff1a;浏览器从输入URL到页面渲染的完整流程中&#xff0c;有哪些关键性能节点&#xff1f; 核心流程&#xff1a;DNS解析 → TCP连接&#xff08;TLS握手&#xff09;→ HTTP请求 → 资源下载 → 解析HT…...

【教程】xrdp修改远程桌面环境为xfce4

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 xfce4 vs GNOME对比 配置教程 1. 安装 xfce4 桌面环境 2. 安装 xrdp 3. 配置 xrdp 使用 xfce4 4. 重启 xrdp 服务 5. 配置防火墙&#xff…...

递增子序列

递增子序列 难点&#xff1a; 结果集如何加&#xff1a;每次进入递归都判断是否sub中的个数>2&#xff1b;不允许对数组排序&#xff0c;如何在每层去重&#xff1a;不可以再用nums[i] nums[i-1]&#xff08;没有意义&#xff0c;重复的元素不一定挨着&#xff09;&#x…...

Linux磁盘管理双雄:lsblk与df深度解析

在Linux系统管理的日常工作里&#xff0c;磁盘管理占据着极为重要的地位&#xff0c;这里重点介绍lsblk和df这两个命令。 一、lsblk命令&#xff1a;呈现磁盘物理架构 lsblk是用于罗列块设备信息的实用命令&#xff0c;它以直观的树状结构呈现系统中的块设备&#xff0c;帮助…...

C#里设计Modbus-RTU(Remote Terminal Unit)协议

Modbus-RTU(Remote Terminal Unit)是一种串行通信协议,广泛用于工业自动化领域,支持主从式(Master-Slave)通信架构。它是Modbus协议的两种传输模式之一(另一种是ASCII模式),具有高效、简洁、可靠性强的特点,常用于RS-485或RS-232物理层通信。 核心特性 物理层 通常基…...

spark学习内容总结

Spark运行架构总结 一、核心结构 Spark框架的核心是一个计算引擎&#xff0c;整体采用标准的master-slave结构。其中&#xff0c;Driver作为master&#xff0c;负责管理整个集群中的作业任务调度&#xff1b;Executor作为slave&#xff0c;负责实际执行任务。 二、核心组件 ‌…...

MySQL多表查询、事务与索引的实践与应用

摘要&#xff1a;本文围绕MySQL数据库操作展开&#xff0c;通过构建部门与员工管理、餐饮业务相关的数据库表&#xff0c;并填充测试数据&#xff0c;系统地阐述了多表查询的多种方式&#xff0c;包括内连接、外连接和不同类型的子查询&#xff0c;同时介绍了事务的处理以及索引…...

MySQL【8.0.41版】安装详细教程--无需手动配置环境

一、MySQL 介绍 1. 概述 MySQL 是一个开源的关系型数据库管理系统&#xff0c;由瑞典公司 MySQL AB 开发&#xff0c;现属于 Oracle 旗下。它基于 SQL&#xff08;结构化查询语言&#xff09;进行数据管理&#xff0c;支持多用户、多线程操作&#xff0c;广泛应用于 Web 应用、…...

FRP练手:hello,world实现

方案一&#xff1a;使用 Flask&#xff08;推荐&#xff09; from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return "你好啊世界"if __name__ __main__:# 监听所有网络接口&#xff08;0.0.0.0&#xff09;&#xff0c;端口 3344app.…...

Mysql | 主从复制的工作机制

主从复制的工作机制 Mysql的主从复制 从库主要是读取主库的binlog日志来完成数据同步的, binlog中存储了对数据库所有修改SQL的语句。 首先Master开启BinLog二进制的写入。Slave从库通过ip、port、账号、密码链接到Master主数据库&#xff0c;链接成功后从库会向主数据库获取B…...

清明之后叙

经历了漫长的冬季&#xff0c;春天的脚步近了&#xff0c;要说讲这一年的开始&#xff0c;绝大数人说是从春季&#xff0c;但是我说应该是从冬季开始&#xff0c;中国传统讲冬至是一阳生&#xff0c;冬季收藏好了&#xff0c;开始收敛精气&#xff0c;养精蓄锐&#xff0c;好好…...

Docker新型容器镜像构建技术,如何正确高效的编写Dockerfile

一、容器与容器镜像之间的关系 说到Docker管理的容器不得不说容器镜像&#xff0c;主要因为容器镜像是容器模板&#xff0c;通过容器镜像我们才能快速创建容器。 如下图所示&#xff1a; Docker Daemon通过容器镜像创建容器。 二、容器镜像分类 操作系统类 CentOSUbuntu在do…...

Starrocks的Bitmap索引和Bloom filter索引以及全局字典

写这个的主要作用是梳理一下Starrocks的索引效率以及使用场景。 Starrocks Bitmap索引 原理&#xff1a; Bitmap 索引是一种使用 bitmap 的特殊数据库索引。bitmap 即为一个 bit 数组&#xff0c;一个 bit 的取值有两种&#xff1a;0 或 1。 每一个 bit 对应数据表中的一行&…...

从 0 到上线:Java 项目打包 Docker 镜像全流程实战

&#x1f4d6; 摘要 本文是一份超详细的Java项目Docker化实战手册&#xff0c;从环境准备到最终上线&#xff0c;手把手带你完成整个容器化部署流程。你将学会&#xff1a; Docker基础概念与核心原理如何为Java项目编写高效的Dockerfile多阶段构建优化镜像体积镜像推送与容器…...

【符号引用和直接引用是什么?有什么作用?什么场景下使用?为什么符号引用和直接引用在常量池里?】

符号引用与直接引用详解 1. 符号引用&#xff08;Symbolic Reference&#xff09; 定义&#xff1a; 符号引用是编译阶段使用的抽象标识符&#xff0c;通过全限定名、方法签名等符号描述目标&#xff08;如类、方法、字段&#xff09;。它不涉及具体内存地址&#xff0c;仅作为…...

ESModule和CommonJS在Node中的区别

ESModule console.log(require);//>errorconsole.log(module);//>errorconsole.log(exports);//>errorconsole.log(__filename);//>errorconsole.log(__dirname);//>error全部报错commonjs console.log(require);console.log(module);console.log(exports);co…...

阿里发布实时数字人项目OmniTalker,实时驱动技术再突破~

简介 OmniTalker 是一个由 阿里巴巴集团 Tongyi Lab&#xff08;通义实验室&#xff09; 开发的研究项目&#xff0c;专注于实时文本驱动的说话头像生成技术。该项目旨在通过文本输入生成同步的语音和视频内容&#xff0c;同时保留参考视频中的音视频风格。以下是关于 OmniTalk…...

Kubernetes-如何进入某POD中

Kubernetes 如何进入某POD中 工作中需要进入pod中查询比如pod 网络等问题 步骤&#xff1a; 1、 查询某pod, 比如该pod 为namespace test 下的 ip 为 192.168.1.100 #查询namespace 列表 #kubectl get ns #查询该ns下ip 为 192.168.1.100的pod # kubectl -n test get pods …...

java导出postgis空间数据几何对象shapefile文件

项目开发中&#xff0c;需要java后端实现导出postgis空间数据几何对象shapefile文件&#xff0c;以便能直观查看数据详情。注意事项Shapefile 默认的几何字段名为 the_geom&#xff0c;若导出时未显式指定或字段名被修改&#xff0c;部分软件&#xff08;如 ArcGIS、QGI&#x…...

蓝桥杯嵌入式按键长按双击

直接上代码这个代码里面我们简单实现了如果按键按下时间超过0.8秒K1的值增加&#xff0c;短按只增加一次&#xff0c;按键2长按K2值增加&#xff0c;按键3双击K1的值减1&#xff0c;按键4双击K2的值减1 #include "fun.h" #define long_press_time 800//定义长按时间…...

深入解析Java中的栈:从JVM原理到开发实践

一、栈的双重身份&#xff1a;JVM运行时数据区 vs 数据结构 1. JVM层面的栈 线程私有&#xff1a;每个线程独立拥有自己的栈 LIFO结构&#xff1a;后进先出的方法调用模型 栈帧存储&#xff1a;每个方法对应一个栈帧&#xff08;Stack Frame&#xff09; 2. 数据结构中的栈…...

408 计算机网络 知识点记忆(6)

前言 本文基于王道考研课程与湖科大计算机网络课程教学内容&#xff0c;系统梳理核心知识记忆点和框架&#xff0c;既为个人复习沉淀思考&#xff0c;亦希望能与同行者互助共进。&#xff08;PS&#xff1a;后续将持续迭代优化细节&#xff09; 往期内容 408 计算机网络 知识…...

从ETL到ELT:大数据时代下两者的选型建议及优势

随着大数据时代的到来&#xff0c;数据量呈爆炸式增长&#xff0c;数据类型日益复杂&#xff0c;ETL与ELT两种技术路径的抉择直接影响着数据处理效率。我们这次来深入解析下两种模式的本质差异与应用场景&#xff0c;为企业提供选型建议。 一、ETL架构的优势 ETL架构遵循“提…...

Java蓝桥杯习题一:for循环和字符串的应用

知道循环次数用for循环 练习题1 小明对数位中含有2.0.1.9的数字很感兴趣&#xff0c;在1到40中这样的数包含1.2.9.10至32.39.40&#xff0c;共28个&#xff0c;他们的和是574.请问&#xff0c;在1到2019中&#xff0c;所有这样的数的和是多少&#xff1f;&#xff08;2019Jav…...

Windows 图形显示驱动开发-WDDM 2.0功能_分配用法跟踪

随着分配列表的消失&#xff0c;视频内存管理器 (VidMm) 不再能够查看特定命令缓冲区中引用的分配。 因此&#xff0c;VidMm 不再能够跟踪分配使用情况和处理相关同步。 此责任现在由用户模式驱动程序 (UMD) 承担。 具体而言&#xff0c;UMD 需要处理与直接 CPU 访问分配和重命…...

SpringMVC的请求-文件上传

文件上传客户端三要素 1. 表单项type“file” 2. 表单的提交方式是post 3. 表单的enctype属性是多部分表单形式&#xff0c;及enctype“multipart/form-data” <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <he…...

MySQL表的增删查改(基础)

一.插入数据 数据准备 create table student(id INT,sn INT comment 学号,name VARCHAR(20) comment 姓名,qq_mail VARCHAR(20) comment QQ邮箱 ); 1.单行数据全列插入 INSERT INTO student VALUES (100, 10000, 唐三藏, NULL); INSERT INTO student VALUES (101, 10001, …...

C++初阶-C++的讲解1

目录 1.缺省(sheng)参数 2.函数重载 3.引用 3.1引用的概念和定义 3.2引用的特性 3.3引用的使用 3.4const引用 3.5.指针和引用的关系 4.nullptr 5.总结 1.缺省(sheng)参数 &#xff08;1&#xff09;缺省参数是声明或定义是为函数的参数指定一个缺省值。在调用该函数是…...

【NLP 面经 9.逐层分解Transformer】

如果我能给你短暂的开心 —— 25.4.7 一、Transformer 整体结构 1.Tranformer的整体结构 Transformer 的整体结构&#xff0c;左图Encoder和右图Decoder&#xff0c;下图是Transformer用于中英文翻译的整体结构&#xff1a; 可以看到 Transformer 由 Encoder 和 Decoder 两个…...

Diffusion Policy Visuomotor Policy Learning via Action Diffusion官方项目解读(二)(5)

运行官方代码库中提供的Colab代码&#xff1a;vision-based environment&#xff08;二&#xff09;&#xff08;5&#xff09; Network十八、类SinusoidalPosEmb&#xff0c;继承自nn.Module十八.1 def __init__()十八.2 def forward()总体说明 十九、类Downsample1d&#xff…...

西门子S7-1200PLC 工艺指令PID_Temp进行控温

1.硬件需求&#xff1a; 西门子PLC&#xff1a;CPU 1215C DC/DC/DC PLC模块&#xff1a;SM 1231 TC模块 个人电脑&#xff1a;已安装TIA Portal V17软件 加热套&#xff1a;带加热电源线以及K型热电偶插头 固态继电器&#xff1a;恩爵 RT-SSK4A2032-08S-F 其他&#xff1…...

【深度学习:理论篇】--Pytorch进阶教程

目录 1.神经网络 1.1.torch.nn 核心模块 1.2.定义神经网络 1.3.损失函数 1.4.反向传播 1.5.梯度更新 2.图片分类器 2.1.数据加载 2.2.卷积神经网络 2.3.优化器和损失 2.4.训练网络 2.5.测试网络 2.6.GPU上训练 3.数据并行训练--多块GPU 3.1.导入和参数 3.2.构造…...

卷积神经网络(CNN)基础

目录 一、应用场景 二、卷积神经网络的结构 1. 输入层&#xff08;Input Layer&#xff09; 2. 卷积层&#xff08;Convolutional Layer&#xff09; 3. 池化层&#xff08;Pooling Layer&#xff09; 最大池化&#xff08;max_pooling&#xff09;或平均池化&#xff08;…...

第 28 场 蓝桥入门赛 JAVA 完整题解

前言 本文总结了六个编程题目的解题思路与核心考点&#xff0c;涵盖基础语法、逻辑分析、贪心算法、数学推导等知识点。每个题目均从问题本质出发&#xff0c;通过巧妙的算法设计或数学优化降低复杂度&#xff0c;展现了不同场景下的编程思维与解题技巧。以下为各题的详细考点解…...

Python 网络请求利器:requests 包详解与实战

诸神缄默不语-个人技术博文与视频目录 文章目录 一、前言二、安装方式三、基本使用1. 发起 GET 请求2. 发起 POST 请求 四、requests请求调用常用参数1. URL2. 数据data3. 请求头 headers4. 参数 params5. 超时时间 timeout6. 文件上传 file&#xff1a;上传纯文本文件流7. jso…...

聊透多线程编程-线程基础-1.进程、线程基础概念

目录 一、进程 二、线程 三、进程与线程的关系 四、进程与线程的比较 注&#xff1a;本文多张图片来源于网络&#xff0c;如有侵权&#xff0c;请联系删除 一、进程 1. 进程的定义 进程是指在系统中正在运行的一个应用程序的实例&#xff0c;是操作系统进行资源分配和调…...

Android:Android Studio右侧Gradle没有assembleRelease等选项

旧版as是“Do not build Gradle task list during Gradle sync” 操作这个选项。 参考这篇文章&#xff1a;Android Studio Gradle中没有Task任务&#xff0c;没有Assemble任务&#xff0c;不能方便导出aar包_gradle 没有task-CSDN博客 在as2024版本中&#xff0c;打开Setting…...

LeetcodeBST2JAVA

235.二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&…...

如何创建单独的城市活码?活码能永久使用吗?

如何创建单独的城市活码 创建单独的城市活码通常需要借助专业的第三方工具&#xff0c;以下是具体步骤&#xff1a; 1.选择合适的工具 推荐使用专业的活码生成工具。 2.注册并登录 访问官网&#xff0c;完成注册并登录。 3.创建活码 在首页点击“创建活码”按钮。输入活码…...

用户画像(https://github.com/memodb-io/memobase)应用

1.下载项目的源代码,我们要先启动后端,用docker启动 cd src/server cp .env.example .env cp ./api/config.yaml.example ./api/config.yaml 这里我的配置内容如下config.yaml(因为我是调用的符合openai格式的大模型,所以我没改,如果要是别的大模型的话,需要自己再做兼容…...

基于形状补全和形态测量描述符的腓骨游离皮瓣下颌骨重建自动规划|文献速递-深度学习医疗AI最新文献

Title 题目 Automated planning of mandible reconstruction with fibula free flap basedon shape completion and morphometric descriptors 基于形状补全和形态测量描述符的腓骨游离皮瓣下颌骨重建自动规划 01 文献速递介绍 因创伤、骨髓炎和肿瘤而接受下颌骨节段切除术…...

Python3笔记之号称替代pip的uv包管理器

uv是什么&#xff1f; uv&#xff0c;这是一个由 Astral 团队开发的极快速的Python包和项目管理工具&#xff0c;用Rust语言编写。它集成了多种功能&#xff0c;旨在替代pip、pip-tools、pipx、poetry、pyenv、twine、virtualenv等多个工具&#xff0c;提供更高效、更全面的Py…...