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

设计模式-visit模式-在语法树的实践

文章目录

      • 背景
      • 示例代码
      • 分析
        • 灵活性
        • 双重分派
      • 总结

背景

很多项目代码有accept()用法,在calcite 里也看到了这种,深入了解一下
语法树遍历:编译器通常会将源代码解析成抽象语法树(AST)。为了实现不同的编译阶段,如语法分析、类型检查、代码生成等,访问者模式非常有用。每个阶段可以有自己的访问者类,而无需修改语法树的结构。
例子:一个编译器可以有 TypeCheckVisitor 用于类型检查,CodeGenVisitor 用于生成目标代码。

示例代码

RexNode 接口的源码有accept方法

public abstract class RexNode {/*** Accepts a visitor, dispatching to the right overloaded* {@link RexVisitor#visitInputRef visitXxx} method.** <p>Also see {@link RexUtil#apply(RexVisitor, java.util.List, RexNode)},* which applies a visitor to several expressions simultaneously.*/public abstract <R> R accept(RexVisitor<R> visitor);
}

定义一个visitor类

package com.demo;import org.apache.calcite.rex.*;public class CustomRexVisitor extends RexVisitorImpl<Void> {public CustomRexVisitor() {super(true);  // true 表示遍历整个树}@Overridepublic Void visitInputRef(RexInputRef inputRef) {System.out.println("Visiting input reference: " + inputRef.getIndex());return null;}@Overridepublic Void visitLiteral(RexLiteral literal) {System.out.println("Visiting literal: " + literal.getValue3());return null;}@Overridepublic Void visitCall(RexCall call) {System.out.println("Visiting call: " + call.getOperator().getName());// 继续遍历子表达式for (RexNode operand : call.getOperands()) {operand.accept(this);}return null;}// 可以重写更多的方法来处理其他类型的节点
}

定义


import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexLiteral;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
import org.apache.calcite.sql.type.SqlTypeName;public class RexVisitorExample {public static void main(String[] args) {// 创建类型工厂RelDataTypeFactory typeFactory = new SqlTypeFactoryImpl(new RelDataTypeSystemImpl() { });// 创建字段类型和字面量类型RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);// 创建字段引用和字面量RexBuilder rexBuilder = new RexBuilder(typeFactory);RexInputRef fieldRef = rexBuilder.makeInputRef(intType, 0);  // 对应字段aRexLiteral literal = rexBuilder.makeLiteral(10, intType);// 创建加法运算表达式RexNode expression = rexBuilder.makeCall(SqlStdOperatorTable.PLUS, fieldRef, literal);// 使用自定义访问者遍历表达式树CustomRexVisitor visitor = new CustomRexVisitor();expression.accept(visitor);}
}

分析

RexNode 有很多种实现,实际上就是打印出来就是一颗语法树,然把在visit 接口类增加对每种数据结构的访问方法,把要实现的具体操作放到visitor 实现类去,达到数据结构和操作之间的解偶。

灵活性

访问者模式的核心思想是通过将操作封装在访问者中,使得可以在不修改数据结构的情况下添加新的操作。这一点通过 accept 方法得以实现。

expression.accept(visitor) 这一调用让表达式树的节点来“接受”一个访问者对象,实际上是节点把自己传递给访问者,由访问者来决定如何处理这个节点。
这意味着访问策略是动态决定的,具体的操作逻辑不再由节点自己决定,而是由传入的访问者对象决定。

双重分派

这个设计背后的一个重要概念是双重分派(Double Dispatch)。
单分派:在普通方法调用中,调用方法的对象类型决定了调用哪个方法,这是一次分派。
双重分派:在访问者模式中,accept 方法的调用对象(即节点)和传入的访问者对象的类型共同决定了最终调用的具体方法。这就是两次分派,或者说双重分派。
在 expression.accept(visitor) 这行代码中:
第一次分派:调用节点的 accept 方法时,由表达式树中的具体节点类型(如 RexLiteral 或 RexCall)决定。
第二次分派:节点将自己传递给访问者,访问者根据节点的具体类型(如 RexLiteral、RexCall 等)选择对应的处理方法(如 visitLiteral、visitCall)。
这意味着操作逻辑不仅依赖于节点的类型,还依赖于传入访问者的类型和访问者的逻辑,从而实现灵活且可扩展的处理方式。

总结

访问者模式和类似的策略模式在面对需要对对象结构进行多种操作时非常有用。它们帮助你在不修改对象结构的情况下增加新的操作逻辑,使代码更容易维护和扩展。这些模式特别适用于那些操作复杂、多变、且具有层次结构的数据结构的场景。

相关文章:

设计模式-visit模式-在语法树的实践

文章目录 背景示例代码分析灵活性双重分派 总结 背景 很多项目代码有accept()用法&#xff0c;在calcite 里也看到了这种&#xff0c;深入了解一下 语法树遍历&#xff1a;编译器通常会将源代码解析成抽象语法树&#xff08;AST&#xff09;。为了实现不同的编译阶段&#xff…...

ZK-Rollups测评

1. 引言 Matter Labs团队和多个高校研究人员一起&#xff0c;发布2024年论文《Analyzing and Benchmarking ZK-Rollups》&#xff0c;开源代码见&#xff1a; https://github.com/StefanosChaliasos/zkrollup-benchmarking&#xff08;Python&#xff09; 其中&#xff1a; …...

redis生产使用场景(一):并行流+二级缓存

本文主要介绍 redis 缓存在线上的使用场景 由于业务的特殊性&#xff0c;在生产库用户表中&#xff0c;大概有 50 多万的测试用户&#xff0c;在真实业务计算中&#xff0c;要把测试用户给筛选掉&#xff0c;所以在计算前&#xff0c;需要把测试用户加载到 redis 缓存中&#x…...

EXCEL跨文件查询,指定条件列,返回满足条件的指定列

EXCEL跨文件查询&#xff0c;指定条件列&#xff0c;返回满足条件的指定列 Private Sub cmd_find_from_workbooks_Click() Dim S_Cols As String, thePath As String, Sor_Col As Integer, sz_Cols As Variant S_Cols T_jieguo_cols.Text sz_Cols Split(S_Cols, ",&quo…...

[数据集][目标检测]流水线物件检测数据集VOC+YOLO格式9255张26类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9255 标注数量(xml文件个数)&#xff1a;9255 标注数量(txt文件个数)&#xff1a;9255 标注…...

StarRocks 存算分离 Compaction 原理

前言 StarRocks 中每次数据摄入都会生成一个新的数据版本&#xff0c;而查询时需要将所有版本数据进行合并才能获得一个正确的结果&#xff0c;如果历史数据版本太多&#xff0c;那么查询时需要读取的文件数也会很多&#xff0c;造成查询效率低下。因而 StarRocks 存在内部任务…...

搭建ELK日志采集与分析系统

SpringCloud微服务实战——企业级开发框架 &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您…...

java集合中自动排序的treeset和treemap

底层 TreeSet 和 TreeMap 的底层架构都是基于红黑树实现的。红黑树是一种自平衡的二叉搜索树,其特性保证了插入、删除和查找操作的时间复杂度为 (O( log ⁡ n \log n logn)),无论数据量多大,操作性能都能保持在合理的范围内。 1. 红黑树概述 红黑树是一种平衡二叉搜索树(…...

Android 修改SystemUI 音量条的声音进度条样式

一、前言 Android System UI 开发经常会遇到修改音量进度条样式的需求&#xff0c;主要涉及的类有VolumeDialogImpl与xml文件&#xff0c;接下来会逐步实现流程。先看看效果。 修改前 修改后 二、找到对应类 通过aidegen 打断点调试对应代码类VolumeDialogImpl定位到volume_d…...

电商场景的视频生成的prompt测评集合

1.收集的一些提示词 一台写着Vidu的赛车在路上飞驰,赛车上面坐着一只乌龟 一个宇航员在太空中骑单车 两个巨大的机器人在打架,电影风格,史诗感,高细节 在科幻电影风格中,两个巨大的机器人在城市废墟中激烈战斗。使用高角度俯拍,展现机器人的宏伟和战斗的史诗感。机器人…...

day34

1 非阻塞型IO 让我们的read函数不再阻塞&#xff0c;无论是否读取到消息&#xff0c;立刻返回 1.1 fcntl函数 原型&#xff1a;int fcntl(int fd, int cmd, ... /* arg */ ); 调用&#xff1a;int flag fcntl(描述符,F_GETFL) fcntl(描述符&#xff0c;F_SETFL&am…...

无缝融入,即刻智能[三]:Dify-LLM平台知识库构建(多路召回、精排重排),43K+星标见证专属智能方案

无缝融入,即刻智能[三]:Dify-LLM平台知识库构建(多路召回、精排重排),43K+星标见证专属智能方案 大语言模型的训练数据一般基于公开的数据,且每一次训练需要消耗大量算力,这意味着模型的知识一般不会包含私有领域的知识,同时在公开知识领域存在一定的滞后性。为了解决这一…...

AWS服务WAF

在 AWS 中使用 Web Application Firewall (WAF) 来防御常见的攻击手段&#xff0c;如 DDoS 攻击和 SQL 注入攻击&#xff0c;可以通过创建和配置规则来实现。下面是如何使用 AWS WAF 阻止这些常见攻击的详细操作步骤。 1. 登录到 AWS 管理控制台 打开 AWS 管理控制台。使用你…...

二叉树中的奇偶树问题

目录 一题目&#xff1a; 二思路汇总&#xff1a; 1.二叉树层序遍历&#xff1a; 1.1题目介绍&#xff1a; 1.2 解答代码&#xff08;c版&#xff09;&#xff1a; 1.3 解答代码&#xff08;c版&#xff09;&#xff1a; 1.4 小结一下&#xff1a; 2.奇偶树分析&#xf…...

GD - EmbeddedBuilder - 用DMA进行串口发送接收,支持接收不定长包

文章目录 GD - EmbeddedBuilder - 用DMA进行串口发送接收&#xff0c;支持接收不定长包概述笔记硬件连接图形化配置485EN的配置串口的图形化配置 代码实现main.cgd32f3x0_hal_it.cgd32f3x0_hal_init.cgd32f3x0_hal_init.hgd32f3x0_hal_it.hgd32f3x0_libopt.h 备注END GD - Embe…...

英语中apartment(公寓)(美式)、house(房子)、flat(公寓)(英式)、villa(别墅)、room(房间)区别

文章目录 英语中apartment、house、flat、villa、room区别 英语中apartment、house、flat、villa、room区别 在英语中&#xff0c;“apartment”、“house”、“flat”、“villa”、和 “room” 这些词语都与居住空间有关&#xff0c;但它们各自的含义和用途有所不同&#xff…...

黑马头条vue2.0项目实战(十一)——功能优化(组件缓存、响应拦截器、路由跳转与权限管理)

1. 组件缓存 1.1 介绍 先来看一个问题&#xff1f; 从首页切换到我的&#xff0c;再从我的回到首页&#xff0c;我们发现首页重新渲染原来的状态没有了。 首先&#xff0c;这是正常的状态&#xff0c;并非问题&#xff0c;路由在切换的时候会销毁切出去的页面组件&#xff…...

《AI视频类工具之一——​ 即创》

一.简介 官网:即创 - 一站式智能创意生产与管理平台 即创是字节跳动(现更名为抖音集团)旗下的一款一站式智能创意生产与管理平台,旨在帮助用户高效地进行创意内容的生成、管理和分析。 二.功能介绍 视频创作: 智能成片:利用AI技术自动编辑视频片段,快速生成完整的视频…...

CSS的:host伪类:精确定位于Web组件的指南

随着Web组件技术的发展&#xff0c;自定义元素&#xff08;Custom Elements&#xff09;已经成为现代Web开发中不可或缺的一部分。CSS的:host伪类为Web组件的样式封装提供了一种强大的工具&#xff0c;它允许开发者为自定义Web组件的宿主元素定义样式。本文将详细介绍:host伪类…...

安卓sdk manager下载安装

安卓sdk下载安装 android SDK manager下载 环境变量配置 ANDROID_HOME&#xff1a;D:\Android %ANDROID_HOME%\tools %ANDROID_HOME%\platform-tools %ANDROID_HOME%\build-tools\29.0.3Android SDK Platform-tools公用开发工具包&#xff0c;需要下载 Android SDK Tools基础…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...