设计模式之解释器模式

一、定义
1、定义
    Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(给定一门语言,定义它的语法的一种表示,并定义一个解释器,该解释器使用该解释来解释语言中的句子。)
2、通用类图

在这里插入图片描述

3、基本介绍
    解释器模式是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)。  在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法解析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器可以看作是解释器。
二、通用源码

解释器角色:

//抽象解释器
public abstract class Expression {//解析任务public abstract Object interpreter(Context ctx);
}

终结符表达式——TerminalExpression:
实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的实例。

//终结符表达式
public class TerminalExpression extends Expression {@Overridepublic Object interpreter(Context ctx) {return null;}
}

非终结符表达式——NonterminalExpression:
文法中的每条规则对应一个非终结表达式。非终结表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

public class NonterminalExpression extends Expression {//每个非终结符表达式都会对其它表达式产生依赖public NonterminalExpression(Expression... expressions){}@Overridepublic Object interpreter(Context ctx) {//进行文法处理return null;}
}
    每个非终结表达式都代表了一个文法规则,并且每个文法规则都只关心自己周边的文法规则的结果,因此这就产生了每个非终结符表达式调用自己周边的非终结符表达式,最终,最小的文法规则就是终结符表达式。  

Client端调用:
通常Client是一个封装类,封装的结果就是传递进来一个规范语法文件,解析器分析后产生结果并返回,避免了调用者与语法解析器的耦合关系。

public class Client {public static void main(String[] args){Context ctx=new Context();//定义一个语法容器,容纳一个具体的表达式;Stack<Expression> stack=null;for (;;){//进行语法分析,并产生递归调用}//产生一个完整的语法树,由各个具体的语法分析进行解析Expression exp=stack.pop();//j具体元素进入场景exp.interpreter(ctx);}
}
三、解释器模式的应用
1、优点
  • 良好的扩展性:修改语法规则只要修改相应的非终结表达式就可以了,若扩展语法,只要增加非终结符类就可以了。
2、缺点
  • 解释器模式会引起类膨胀:每一个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来许多麻烦。
  • 效率问题:解释器模式由于使用了大量的循环和递归,效率是一个不容忽视的问题。
3、使用场景
  • 重复发生的问题可以使用解释器模式:例如,多个应用服务器,需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相通的,但是非终结符表达式就需要制定了。在这种情况下,可以通过解释器模式一劳永逸的解决该问题。
  • 一个简单语法需要解释的场景:一般用于解析比较标准的字符集,例如SQL语法分析。
四、SpelExpressionParser中解释器模式应用分析
1、类图分析
    在下面的类图中,Expression是一个接口,相当于我们解释器模式中的非终结符表达式,而ExpressionParser相当于终结符表达式。根据不同的Parser对象,返回不同的Expression对象。  

在这里插入图片描述

2、部分源码分析

Expression接口:

//抽象的非终结符表达式
public interface Expression {Object getValue() throws EvaluationException;Object getValue(Object rootObject) throws EvaluationException;
}

SpelExpression类:

//具体的非终结符表达式
public class SpelExpression implements Expression {@Overridepublic Object getValue() throws EvaluationException {Object result;if (this.compiledAst != null) {try {TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject();return this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext);}catch (Throwable ex) {// If running in mixed mode, revert to interpretedif (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {this.interpretedCount = 0;this.compiledAst = null;}else {// Running in SpelCompilerMode.immediate mode - propagate exception to callerthrow new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);}}}ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);result = this.ast.getValue(expressionState);checkCompile(expressionState);return result;}}

CompositeStringExpression:

//具体的非终结符表达式
public class CompositeStringExpression implements Expression {@Overridepublic String getValue() throws EvaluationException {StringBuilder sb = new StringBuilder();for (Expression expression : this.expressions) {String value = expression.getValue(String.class);if (value != null) {sb.append(value);}}return sb.toString();}
}

ExpressionParser接口:

public interface ExpressionParser {//解析表达式Expression parseExpression(String expressionString) throws ParseException;Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}

TemplateAwareExpressionParser类:

public abstract class TemplateAwareExpressionParser implements ExpressionParser {@Overridepublic Expression parseExpression(String expressionString) throws ParseException {return parseExpression(expressionString, NON_TEMPLATE_PARSER_CONTEXT);}//根据不同的parser返回不同的Expression对象@Overridepublic Expression parseExpression(String expressionString, ParserContext context)throws ParseException {if (context == null) {context = NON_TEMPLATE_PARSER_CONTEXT;}if (context.isTemplate()) {return parseTemplate(expressionString, context);}else {return doParseExpression(expressionString, context);}}private Expression parseTemplate(String expressionString, ParserContext context)throws ParseException {if (expressionString.length() == 0) {return new LiteralExpression("");}Expression[] expressions = parseExpressions(expressionString, context);if (expressions.length == 1) {return expressions[0];}else {return new CompositeStringExpression(expressionString, expressions);}}//抽象的,由子类去实现protected abstract Expression doParseExpression(String expressionString,ParserContext context) throws ParseException;
}

SpelExpressionParser类:

public class SpelExpressionParser extends TemplateAwareExpressionParser {@Overrideprotected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {//这里返回了一个InternalSpelExpressionParser,return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);}}

InternalSpelExpressionParser类:

class InternalSpelExpressionParser extends TemplateAwareExpressionParser {@Overrideprotected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {try {this.expressionString = expressionString;Tokenizer tokenizer = new Tokenizer(expressionString);tokenizer.process();this.tokenStream = tokenizer.getTokens();this.tokenStreamLength = this.tokenStream.size();this.tokenStreamPointer = 0;this.constructedNodes.clear();SpelNodeImpl ast = eatExpression();if (moreTokens()) {throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken()));}Assert.isTrue(this.constructedNodes.isEmpty());return new SpelExpression(expressionString, ast, this.configuration);}catch (InternalParseException ex) {throw ex.getCause();}}
}

本文转自 https://blog.csdn.net/qq_42339210/article/details/107595568,如有侵权,请联系删除。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/139144.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Winform直接与Wpf交互

Winform项目中&#xff0c;可以直接使用wpf中的自定义控件和窗体 测试环境&#xff1a; vistual studio 2017 window 10 一 winform直接使用wpf的自定义控件 步骤如下&#xff1a; 1 新建winfrom项目&#xff0c;名为WinFormDemo&#xff0c;默认有一个名为Form1的窗体…

【GAMES103】基于物理的计算机动画入门(1)前置的基础数学知识

GAMES103: 基于物理的计算机动画入门 链接&#xff1a;GAMES103 1. 坐标系的划分 在游戏引擎中分为右手和左手坐标系&#xff0c;区分的依据是什么&#xff1f; 上图可以看到如果是左手坐标系&#xff0c;那么所有的物体都在屏幕后面&#xff0c;意味着x&#xff0c;y&#x…

物联网的未来:连接的智能世界

物联网&#xff08;IoT&#xff09;是引领我们走向未来的一项关键技术。它让物品通过互联网进行连接&#xff0c;交流&#xff0c;开创了智能生活新时代。预计到2025年&#xff0c;全球将拥有超过410亿的IoT设备。在对人类生活的每个方面产生影响的同时&#xff0c;物联网也正在…

2023华为杯研究生数学建模竞赛CDEF题思路+模型代码

全程更新华为杯研赛CDEF题思路模型及代码&#xff0c;大家查看文末名片获取 华为杯C题思路分析 问题一 在每个评审阶段&#xff0c;作品通常都是随机分发的&#xff0c;每份作品需要多位评委独立评审。为了增加不同评审专家所给成绩之间的可比性&#xff0c;不同专家评审的作…

【kafka实战】03 SpringBoot使用kafka生产者和消费者示例

本节主要介绍用SpringBoot进行开发时&#xff0c;使用kafka进行生产和消费 一、引入依赖 <dependencies><dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId></dependency><depen…

zabbix自定义监控、钉钉、邮箱报警

目录 一、实验准备 二、安装 三、添加监控对象 四、添加自定义监控项 五、监控mariadb 1、添加模版查看要求 2、安装mariadb、创建用户 3、创建用户文件 4、修改监控模版 5、在上述文件中配置路径 6、重启zabbix-agent验证 六、监控NGINX 1、安装NGINX&#xff0c…

207.Flink(二):架构及核心概念,flink从各种数据源读取数据,各种算子转化数据,将数据推送到各数据源

一、Flink架构及核心概念 1.系统架构 JobMaster是JobManager中最核心的组件,负责处理单独的作业(Job)。一个job对应一个jobManager 2.并行度 (1)并行度(Parallelism)概念 一个特定算子的子任务(subtask)的个数被称之为其并行度(parallelism)。这样,包含并行子任…

实验五 熟悉 Hive 的基本操作

实验环境&#xff1a; 1.操作系统&#xff1a;CentOS 7。 2.Hadoop 版本&#xff1a;3.3.0。 3.Hive 版本&#xff1a;3.1.2。 4.JDK 版本&#xff1a;1.8。 实验内容与完成情况&#xff1a; &#xff08;1&#xff09;创建一个内部表 stocks&#xff0c;字段分隔符为英文逗号…

爬虫 — Scrapy 框架(一)

目录 一、介绍1、同步与异步2、阻塞与非阻塞 二、工作流程三、项目结构1、安装2、项目文件夹2.1、方式一2.2、方式二 3、创建项目4、项目文件组成4.1、piders/__ init __.py4.2、spiders/demo.py4.3、__ init __.py4.4、items.py4.5、middlewares.py4.6、pipelines.py4.7、sett…

BOM与DOM--记录

BOM基础&#xff08;BOM简介、常见事件、定时器、this指向&#xff09; BOM和DOM的区别和联系 JavaScript的DOM与BOM的区别与用法详解 DOM和BOM是什么&#xff1f;有什么作用&#xff1f; 图解BOM与DOM的区别与联系 BOM和DOM详解 JavaScript 中的 BOM&#xff08;浏览器对…

睿趣科技:抖音开通蓝V怎么操作的

在抖音这个充满创意和活力的社交媒体平台上&#xff0c;蓝V认证成为了许多用户的梦想之一。蓝V认证不仅是身份的象征&#xff0c;还可以增加用户的影响力和可信度。但是&#xff0c;要在抖音上获得蓝V认证并不是一件容易的事情。下面&#xff0c;我们将介绍一些操作步骤&#x…

小米笔试题——01背包问题变种

这段代码的主要思路是使用动态规划来构建一个二维数组 dp&#xff0c;其中 dp[i][j] 表示前 i 个产品是否可以组合出金额 j。通过遍历产品列表和可能的目标金额&#xff0c;不断更新 dp 数组中的值&#xff0c;最终返回 dp[N][M] 来判断是否可以组合出目标金额 M。如果 dp[N][M…

Android studio安卓生成APK文件安装包方法

1.点击Build->Generate Signed Bundle/APK 2.选择APK 3.首次生成&#xff0c;没有jks文件&#xff0c;就点击Create new。再次生成&#xff0c;直接点Next 4.选择创建jks文件路径 5.点击Next 6.选择release 7.生成完成的apk安装包路径

【论文阅读 08】Adaptive Anomaly Detection within Near-regular Milling Textures

2013年&#xff0c;太老了&#xff0c;先不看 比较老的一篇论文&#xff0c;近规则铣削纹理中的自适应异常检测 1 Abstract 在钢质量控制中的应用&#xff0c;我们提出了图像处理算法&#xff0c;用于无监督地检测隐藏在全局铣削模式内的异常。因此&#xff0c;我们考虑了基于…

uniapp小程序点击按钮直接退出小程序效果demo(整理)

点击按钮直接退出小程序 <navigator target"miniProgram" open-type"exit">退出小程序</navigator>

Android Key/Trust Store研究+ssl证书密钥

前言&#xff1a;软件搞环境涉及到了中间件thal trustzone certificate key&#xff0c;翻译过来是thal信任区域证书密钥 &#xff0c;不明白这是什么&#xff0c;学习一下 ssl证书密钥 SSL密钥是SSL加密通信中的重要组成部分。SSL证书通过加密算法生成&#xff0c;用于保护网…

Oracle 11g RAC部署笔记

搭了三次才搭好&#xff0c;要记录一下。 1. Oracle 11g RAC部署的相关步骤以及需要的包&#xff0c;可以参考这里。 Oracle 11g RAC部署_12006142的技术博客_51CTO博客Oracle 11g RAC部署&#xff0c;Oracle11gRAC部署操作环境&#xff1a;CentOS7.4Oracle11.2.0.4一、主机网…

解决老版本Oracle VirtualBox 此应用无法在此设备上运行问题

问题现象 安装华为eNSP模拟器的时候&#xff0c;对应的Oracle VirtualBox-5.2.26安装的时候提示兼容性问题&#xff0c;无法进行安装&#xff0c;具体版本信息如下&#xff1a; 软件对应版本备注Windows 11专业工作站版22H222621eNSP1.3.00.100 V100R003C00 SPC100终结正式版…

利用优化算法提高爬虫任务调度效率

目录 一、任务调度优化的重要性 二、选择合适的优化算法 三、建立任务调度模型 四、设计适应性函数 五、算法实施和调优 六、性能评估和优化结果分析 代码示例 总结 随着网络信息的爆炸式增长&#xff0c;网络爬虫在信息获取和数据挖掘等领域的应用越来越广泛。然而&am…

Arduino程序设计(十一)8×8 共阳极LED点阵显示(74HC595)

88 共阳极LED点阵显示 前言一、74HC595点阵模块1、74HC595介绍2、74HC595工作原理3、1088BS介绍4、74HC595点阵模块 二、点阵显示实验1、点阵显示初探2、点阵显示进阶3、点阵显示高阶3.1 点阵显示汉字&#xff08;方法1&#xff09;3.2 点阵显示汉字&#xff08;方法2&#xff…