设计模式之解释器模式
阅读建议
嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:
- 本篇文章大概5000多字,预计阅读时间长需要5分钟。
- 本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
- 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。
什么是解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例,其核心原理是将一个语言表达式表示为一个抽象语法树,然后定义解释器来遍历这棵语法树并执行相应的操作。
是的,没有看错,这就是解释器模式的标准定义,是不是和我一样,看完后完全处于懵逼状态,这里语言是什么?文法又是什么?语法树是什么?解释器是怎么解释句子的?...讲真的,解释器模式确实不太好理解。
复杂的事情,慢慢来理解,先来弄懂标题解释器是什么意思?
解释器(Interpreter)是一种电脑程序,能够把高级编程语言一行一行直接转译运行。实际它是一种翻译程序,执行方式是一边翻译一边执行。什么意思呢?再具体来说,比如JavaScript、Python就属于解释型语言,如下面的python代码,打印输出“hello world”,在计算机里是怎么运行呢?首先,计算机能够理解并执行的指令是二进制的,这些高级字符肯定是不直接执行的,因此在执行前,这句代码会通过python环境中的解释器解释成计算机可以理解的二进制指令,如果语法有问题,解释的过程就会出现异常,程序执行会中断。而Java是属于编译型的,什么意思呢?就是先把.java文件编译成.class文件然后再加载到虚拟机执行。
print("Hello, world!")
找到标题的出处后,后面的定义内容就好理解多了。
- 语言:python就是一门编程语言,汉语就是一门中国人之间直接交流的语言;
- 文法:就是语法,python有自己语法,遵循语法规范,程序才能正确解释并执行。汉语也有,一般就是主谓宾那一套;
- 句子:对于python来说,print("Hello, world!"),就一句话。对于汉语来说,“我爱你,中国!”也是一个句子;
- 语法树:语法树是句子结构的一种树型表示,比如:我爱你,中国!这句话照汉语的语法表示为一个树型结果就是:
解释器模式有哪些核心角色
解释器模式的核心角色主要包括以下四个:
- 抽象表达式(IExpression):这是解释器模式中的核心接口,负责定义解释方法interpret,交由具体子类进行具体解释。
/*** 抽象表达式*/
public abstract class AbstractExpression {public abstract boolean interpret(String info);
}
- 终结符表达式(TerminalExpression):这是抽象表达式的子类,实现了与文法中终结符相关的解释操作。通常一个解释器中只有一个终结符表达式,但有多个实例,对应不同的终结符。
/*** 终结符表达式*/
public class TerminalExpression extends AbstractExpression{private String data;public TerminalExpression(String data) {this.data = data;}@Overridepublic boolean interpret(String info) {return info.contains(data);}
}
- 非终结符表达式(NonterminalExpression):这也是抽象表达式的子类,实现了文法中与非终结符相关的解释操作。
/*** 非终结符表达式*/
public class NonterminalExpression extends AbstractExpression {private AbstractExpression expr1;private AbstractExpression expr2;public NonterminalExpression(AbstractExpression expr1, AbstractExpression expr2) {this.expr1 = expr1;this.expr2 = expr2;}@Overridepublic boolean interpret(String info) {return expr1.interpret(info) || expr2.interpret(info);}
}
- 上下文环境类(Context):这个类主要用来存放解释器之外的全局信息,一般用来存放文法中各个终结符所对应的具体值。
/*** 上下文环境类*/
public class Context {private AbstractExpression expression;public Context(AbstractExpression expression) {this.expression = expression;}public void interpret(String info){System.out.println(info);boolean interpret = this.expression.interpret(info);if (interpret) {System.out.println("结束");}}
}
/*** 客户端*/
public class Client {public static void main(String[] args) {AbstractExpression expre1=new TerminalExpression("\n");AbstractExpression expre2=new TerminalExpression("\r");AbstractExpression expre=new NonterminalExpression(expre1,expre2);Context context=new Context(expre);context.interpret("hello ,world!\n");}
}
解释器模式如何实现
需求描述
这篇文章是设计模式系列的最后一篇,之所以放在最后一篇是因为我觉得理解起来比较困难和抽象。当然,如果你能够跟上我的思路,到这里也许已经明白其中的一二,再举一个实际的例子,来模拟解释器模式的实现,看完之后,也许就全明白了。
现在直播带货是真的火,有的主播,随随便便一场直播,就够普通打工人干一辈子的了,也正因此,无数人开始蜂拥而入,更有很多人为了圈钱,更是没有底线的蹭热点、制造热点。人多了,那么问题就出现了:在直播间里,有的人比较喜欢这个主播,,则是“我爱你xxx”、“xxx,我支持你”之类的各种弹幕满屏飞,有的人不喜欢这个主播,则是各种诋毁和谩骂,那么如果需要对所有要输出打印到公屏上的弹幕做一个敏感词的过滤,应该怎么做呢?如果使用解释器模式,则可以这样实现:
实现方法
1、AbstractExpression.java:声明一个抽象表达式(IExpression):在抽象类里,定义解释方法interpret,由具体敏感词表达式、非敏感词表达工子类进行具体实现。
/*** 抽象表达式*/
public abstract class AbstractExpression {public abstract boolean interpret(String info);
}
2、SensitiveExpression.java、NonsensitiveExpresson.java:声明具体的敏感词表达式类、非敏感词表达式类,实现具体的解释逻辑;
/*** 敏感词表达式*/
public class SensitiveExpression extends AbstractExpression {private String data;public SensitiveExpression(String data) {this.data = data;}@Overridepublic boolean interpret(String info) {return info.contains(data);}
}
/*** 非敏感词表达式*/
public class NonsensitiveExpression extends AbstractExpression {private AbstractExpression expr1;private AbstractExpression expr2;public NonsensitiveExpression(AbstractExpression expr1, AbstractExpression expr2) {this.expr1 = expr1;this.expr2 = expr2;}@Overridepublic boolean interpret(String info) {return expr1.interpret(info) || expr2.interpret(info);}
}
3、Context.java:上下文环境类(Context),持有具体的表达式实现。
/*** 上下文环境类*/
public class Context {private AbstractExpression expression;public Context(AbstractExpression expression) {this.expression = expression;}public void print(String info) {boolean interpret = this.expression.interpret(info);if (interpret) {System.out.println("忽略敏感词:*****");} else {System.out.println("XXXX说:"+info);}}
}
4、编写业务客户端进行测试验证
/*** 客户端*/
public class Client {public static void main(String[] args) {AbstractExpression expre1=new SensitiveExpression("滚");AbstractExpression expre2=new SensitiveExpression("垃圾");AbstractExpression expre=new NonsensitiveExpression(expre1,expre2);Context context=new Context(expre);context.print("支持主播");context.print("主播垃圾");context.print("主播真漂亮");context.print("主播滚蛋");}
}
解释器模式适用哪些场景
解释器模式的应用场景包括但不限于以下几种情况:
- 表达式求值:例如计算器应用、公式计算、数据分析等,解释器可以将表达式解析成计算机可以执行的指令。
- 自然语言处理:例如语言翻译、语音识别、虚拟助手等,解释器可以将人类语言翻译成计算机可以识别的语言。
- 日志处理:使用脚本语言或编程语言处理日志时,有很多服务会产生大量的日志,需要对日志进行解析,生成报表。各个服务的日志格式不同,数据中的要素相同,这种情况下,通过程序解决上述问题,主要的解决方案就是使用解释器模式。
解释器模式的优点和缺点
优点
- 易于改变和扩展文法:由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 每一条文法规则都可以表示为一个类:因此可以方便地实现一个简单的语言。
- 增加新的解释表达式较为方便:如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。
缺点
- 对于复杂文法难以维护:在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护。
- 执行效率较低:由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。
总结
总之,在表达式求值、自然语言处理和日志处理等业务场景中,解释器模式可以将人类语言或非编程语言转换为计算机可执行的语言,从而实现对数据的解析、处理和计算等功能,是一种行之有效的设计模式,但是其本身复杂性和核心原理需要特别注意。
相关文章:

设计模式之解释器模式
阅读建议 嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议: 本篇文章大概5000多字,预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章&#x…...

粉够荣获淘宝联盟区域理事会常务理事,携手共铸淘客新生态
淘宝联盟区域理事会于2021年成立,首届成立成都、广州、武汉,服务近2000个领军淘宝客企业,作为区域生态与官方交流重要枢纽,理事会举办近百场交流分享会,带动淘客跨域跨业态交流成长。 2023年9月7日第二届淘宝联盟理事…...
Python爬虫是否合法?
Python爬虫是否合法的问题颇具争议,主要涉及到使用爬虫的目的、操作方式以及是否侵犯了其他人的权益。本文将介绍Python爬虫的合法性问题,并提供一些相关的法律指导和最佳实践。 1. 什么是Python爬虫? Python爬虫是一种自动化程序ÿ…...
3.2 IDAPro脚本IDC常用函数
IDA Pro内置的IDC脚本语言是一种灵活的、C语言风格的脚本语言,旨在帮助逆向工程师更轻松地进行反汇编和静态分析。IDC脚本语言支持变量、表达式、循环、分支、函数等C语言中的常见语法结构,并且还提供了许多特定于反汇编和静态分析的函数和操作符。由于其…...

用python将csv表格数据做成热力图
python的开发者为处理表格和画图提供了库的支持,使用pandas库可以轻松完成对csv文件的读写操作,使用matplotlib库提供了画热力图的各种方法。实现这个功能首先需要读出csv数,然后设置自定义色条的各种属性如颜色,位置,…...
【程序基础】递归法
算法思想 递归法,其实可以说是一种编程技巧,通过调用自身,防止无限循环而给予递归出口。 思考使用场景 1.一个问题可以拆分成子问题,每个子问题相互独立。 2.数据满足递推关系,或者数据结构满足,例如图&…...

AI 绘画 | Stable Diffusion WebUI的基本设置和插件扩展
前言 Stable Diffusion WebUI是一个基于Gradio库的浏览器界面,用于配置和生成AI绘画作品,并且进行各种精细地配置。它支持目前主流的开源AI绘画模型,例如NovelAI/Stable Diffusion。 在基本设置方面,Stable Diffusion WebUI的默…...

如何用自然语言 5 分钟构建个人知识库应用?我的 GPTs builder 尝试
开发者的想象力闸门一旦打开,迎接我们的必然是目不暇接的 AI 应用浪潮冲击。 兴奋 早晨,我突然发现 ChatGPT 最新的 Create GPTs 功能可以用了。 这太让我意外了,没想到这么快。根据页面上的提示,我一直以为还得等上一周左右。于是…...
rabbitmq启动异常解决
如果 RabbitMQ 节点一直停在 "Stopping and halting node" 阶段,可能是由于一些原因导致节点无法正常停止。以下是一些建议的步骤,以尝试解决此问题: 手动强制终止节点: 尝试使用 rabbitmqctl 命令手动终止节点。在终端…...

OpenGL_Learn08(坐标系统与3D空间)
目录 1. 概述 2. 局部空间 3. 世界空间 4. 观察空间 5. 剪裁空间 6. 初入3D 7. 3D旋转 8. 多个正方体 9. 观察视角 1. 概述 OpenGL希望在每次顶点着色器运行后,我们可见的所有顶点都为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说&#x…...

github私有仓库开发,公开仓库发布版本
文章目录 github私有仓库开发,公开仓库发布版本需求背景实现思路GitHub Releases具体步骤广告 github私有仓库开发,公开仓库发布版本 需求背景 github私有仓库开发,公开仓库发布版本,既可以保护源代码,又可以发布版本给用户使用。许多知名软件项目都采用了这样的开…...

绿色低碳 数字未来-辽宁省建筑电气2023年学术年会-安科瑞 蒋静
2023年8月18日,辽宁省建筑电气2023年学术年会在辽宁友谊国宾馆成功召开。本届大会以“绿色低碳 数字未来”为主题,着眼为辽宁省建设提供智慧化电气设计及高质量产品服务。 安科瑞围绕“绿色低碳 数字未来”的主题,携充电桩及运营管理平台、工…...
day55
今日内容概要 路由层 无名分组 有名分组 反向解析 无名分组反向解析 有名分组反向解析 路由分发 伪静态的概念(了解) 名称空间(了解) 虚拟环境(了解) django1.x和django2.x的区别 路由层 url(r^test/$, views.test), url(rtestadd, views.testadd), ## 首页的地址 u…...

如何安装Node.js? 创建Vue脚手架
1.进入Node.js官网,点击LTS版本进行下载 Node.js (nodejs.org)https://nodejs.org/en 2.然后一直【Next】即可 3.打开【cmd】,输入【node -v】注意node和-v中间的空格 查看已安装的Node.js的版本号,如果可以看到版本号,则安装成功 创建Vue脚手…...

ASP.NETWeb开发(C#版)-day1-C#基础+实操
目录 .NET实操:创建项目执行 C#基础语法数据类型变量实操001_变量如何在一个解决方案 中创建另一个项目实操002结构实操003-if else实操004-多分支多行注释按钮实操:循环 面向对象基础如何在同一个项目下创建新的.cs文件实操-类的定义与访问实操-练习实操…...
LGSVL Python API 使用
1. References [1] LGSVL-python API使用方法 - 简书 [2] GitHub - lgsvl/PythonAPI: Python API for Simulator...

详解数据仓库之拉链表(原理、设计以及在Hive中的实现)
最近发现一本好书,读完感觉讲的非常好,首先安利给大家,国内第一本系统讲解数据血缘的书!点赞!近几天也会安排朋友圈点赞赠书活动(ง•̀_•́)ง 0x00 前言 本文将会谈一谈在数据仓库中拉链表相关的内容,包…...

使用Nodejs搭建简单的web网页并实现公网访问
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 使用Nodejs搭建简单的web网页并实现公网访问 前言 Node.js是建立在谷歌Chrome的JavaScript引擎…...

C++学习第三十七天----第十章--对象和类
10.2.2 C中的类 类是一种将抽象转换未用户定义类型的C工具,它将数据表示和操作数据的方法合成一个整洁的包。 接口:一个共享框架,供两个系统交互时使用。 1.访问控制 使用类对象的程序可以直接访问类的公有部分,但只能通过公有…...

TikTok影响力经济:解锁社交媒体的商业机遇
社交媒体平台的崛起改变了我们与世界互动的方式,而TikTok作为其中的一员,已经成为全球范围内的现象。这个短视频应用不仅让用户在几秒钟内分享创意和娱乐,还为企业和创作者提供了巨大的商业机会。本文将深入探讨TikTok的影响力经济࿰…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...