解析器模式:面向对象设计中的表达式评估与语法树构建策略

解释器模式(Interpreter Pattern)是一种行为设计模式,它定义了一种语言,并使用该语言来解释句子。这种模式用于描述如何构成一个简单的语言解析器。在Java中实现解释器模式通常涉及一个抽象表达式接口、具体表达式类(终端表达式和非终端表达式)、以及上下文环境类。
在这里插入图片描述

  • AbstractExpression 是所有表达式的抽象基类,声明了一个 interpret() 方法,用于解释操作。
  • TerminalExpression 是最终表达式类,实现了具体的解释逻辑。
  • NonTerminalExpression 是非终极表达式类,除了实现 interpret() 方法外,还可能包含组合其他表达式的方法(如 add() 或 setNext()),用于构建更复杂的表达式结构。
  • Context 类包含了表达式解释所需的环境信息,供表达式在解释时使用。

实现四则运算

我们使用解释器模式实现了一个简单的算术表达式求值功能。Interpreter类的evaluate()方法接受一个字符串形式的表达式,然后通过栈和递归的方式解析并计算表达式的值。

  1. 首先,我们定义一个表达式接口Expression,它有一个解释方法interpret():
public interface Expression {int interpret(HashMap<String,Integer> map);
}
  1. 创建两个具体的表达式类:最终表达式NumberExpression和非终极表达式AddExpression,分别表示数字和加法操作。他们都从map中获取值所需要的值:
public class NumberExpression implements Expression {private String key;public NumberExpression(String key) {this.key = key;}@Overridepublic int interpret(HashMap<String,Integer> map) {return map.get(key);}
}private Expression leftExpression;private Expression rightExpression;public AddExpression(Expression leftExpression, Expression rightExpression) {this.leftExpression = leftExpression;this.rightExpression = rightExpression;}@Overridepublic int interpret(HashMap<String, Integer> map) {return leftExpression.interpret(map)+rightExpression.interpret(map);}

同样的写一个减法:

public class SubExpression implements Expression {private Expression leftExpression;private Expression rightExpression;public SubExpression(Expression leftExpression, Expression rightExpression) {this.leftExpression = leftExpression;this.rightExpression = rightExpression;}@Overridepublic int interpret(HashMap<String, Integer> map) {return leftExpression.interpret(map) - rightExpression.interpret(map);}
}
  1. 我们创建一个解释器类Interpreter,用于解释表达式。然后通过栈和递归的方式解析并计算表达式的值:
import java.util.Stack;public class Interpreter {public Expression expression;
/*** Interpreter类用于解析并执行给定的表达式。* * @param expression 表达式字符串,支持加减运算和整数。*/
public Interpreter(String expression) {Stack<Expression> stack = new Stack<>();char[] tokens = expression.toCharArray();for (int i = 0; i < tokens.length; i++) {if ('+' == tokens[i]) {// 当遇到加号时,从栈中弹出右操作数,创建一个加法表达式并压入栈中Expression rightExpression = stack.pop();Expression leftExpression = new NumberExpression(String.valueOf(tokens[++i]));stack.push(new AddExpression(leftExpression, rightExpression));} else if ('-' == tokens[i]) {// 当遇到减号时,从栈中弹出右操作数,创建一个减法表达式并压入栈中Expression rightExpression = stack.pop();Expression leftExpression = new NumberExpression(String.valueOf(tokens[++i]));stack.push(new SubExpression(leftExpression, rightExpression));} else {// 遇到其他字符(假设为数字)时,创建一个数字表达式并压入栈中stack.push(new NumberExpression(String.valueOf(tokens[i])));}}this.expression = stack.pop(); // 最后栈中剩下的就是解析后的表达式
}/*** 执行解析后的表达式,并返回结果。* * @param map 用于解析表达式中变量的值的映射。* @return 表达式的计算结果。*/
public int run(HashMap<String, Integer> map) {return this.expression.interpret(map);
}
}
  1. 使用:
  @Testvoid contextLoads() {HashMap<String, Integer> map = new HashMap<>();map.put("a", 10);map.put("b", 20);map.put("c", 30);String expression = "a+b-c";Interpreter in = new Interpreter(expression);int run = in.run(map);System.out.println(run);//0}

解释器模式 优缺点

解释器模式的优点主要包括:

  • 扩展性好:由于使用类来表示语言的文法规则,可以通过继承等机制来改变或扩展文法。
  • 易于实现简单文法:在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。

解释器模式的缺点包括:

  • 执行效率较低:通常使用大量的循环和递归调用,当要解释的句子较复杂时,运行速度很慢,且代码的调试过程也比较麻烦。
  • 引起类膨胀:每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
  • 应用场景少:在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。

典型应用

Expression4J是一个Java库,它允许你解析和执行数学表达式。这个库是设计模式应用的一个很好的例子,因为它使用解释器模式来处理和计算表达式:

  • 文法表示:Expression4J定义了一套规则来描述数学表达式的结构和语法。
  • 解释器构建:该库包含一个解释器,它能够理解这些规则并将输入的表达式转换为可执行的代码。
  • 上下文环境:在解释器模式中,通常会有一个环境类来存储全局信息,这可能是以HashMap的形式实现的。虽然Expression4J的具体实现细节可能不同,但概念上它提供了一种方式来管理表达式求值所需的上下文信息。
  • 适用场景:解释器模式适用于那些需要频繁解释特定类型语言的问题。由于Expression4J是为了解决数学表达式求值这一问题而设计的,它正好符合解释器模式的应用场景。

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

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

相关文章

HCIP课后习题之一

1、路由协议用工作机制上分为那几种&#xff1f;分别是&#xff1f; A&#xff1a;两种。分别是静态路由和动态路由&#xff08;可分为IGP和EGP&#xff09; 2、IGP和EGP协议有哪些&#xff1f; A&#xff1a;IGP: RIP、OSPF、ISIS、EIGRP EGP: BGP 3、路由优先级的用途&…

Leetcode - 周赛392

目录 一&#xff0c;3105. 最长的严格递增或递减子数组 二&#xff0c;3106. 满足距离约束且字典序最小的字符串 三&#xff0c;3107. 使数组中位数等于 K 的最少操作数 四&#xff0c;3108. 带权图里旅途的最小代价 一&#xff0c;3105. 最长的严格递增或递减子数组 本题求…

Steam平台游戏发行流程

Steam平台游戏发行流程 大家好我是艾西&#xff0c;一个做服务器租用的网络架构师也是游戏热爱者&#xff0c;经常在steam平台玩各种游戏享受快乐生活。去年幻兽帕鲁以及雾锁王国在年底横空出世&#xff0c;幻兽帕鲁更是在短短一星期取得了非常好的成绩&#xff0c;那么作为游戏…

Python工程师面试高频题:return 和 yield之间到底有啥区别?

在编程语言 Python 中&#xff0c;yield 和 return 是两个在函数中用于返回值的关键字&#xff0c;但它们在功能和使用场景上有着本质的区别。理解这两者的区别&#xff0c;对于编写更高效、更灵活的 Python 代码至关重要。 看图说话 首先我们来看下面这张图片&#xff0c;该…

【C++】STL学习之vector的使用

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言一、默认成员函数1.1 默认构造1.2 拷贝构造1.3 析构函数1.4 赋值重载 二、迭…

系统架构最佳实践 -- 金融企业的资损防控

一、资损产生的原因 由于支付行业的特殊性与复杂性&#xff08;主要处理资金相关业务&#xff09;&#xff0c;支付公司处于资损的风口浪尖&#xff0c;最容易发生资损&#xff0c;可以说资损风险无处不在。 常规来说&#xff0c;资损原因主要可以分为以下三类&#xff1a; 1…

【数据结构】树与二叉树遍历算法的应用(求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子)

目录 求叶子节点个数、求树高、复制二叉树、创建二叉树、二叉树存放表达式、交换二叉树每个结点的左右孩子应用一&#xff1a;统计二叉树中叶子结点个数的算法写法一&#xff1a;使用静态变量写法二&#xff1a;传入 count 作为参数写法三&#xff1a;不使用额外变量 应用二&am…

Mybatis中SqlSession接口中的selectList方法

1、SqlSession SqlSession是Mybatis持久层框架提供的接口&#xff0c;该接口中包含了大量的CRUD操作方法&#xff08;既增删改查方法&#xff09;。 2、selectList方法 selectList方法是用于查询的方法&#xff0c;该方法具有多态性&#xff0c;如图所示&#xff08;打开myb…

使用cmake进行打包,包含可执行程序和动态依赖库

平常代码开发中&#xff0c;有时候需要将写的程序打包成压缩包放到目标设备上进行运行测试。用CMake管理工程&#xff0c;实现使用make -jnproc package指令可以将工程进行打包&#xff0c;可执行文件存储在bin文件夹中&#xff0c;依赖库存储在lib文件夹中。 示例 1.工程目录结…

靠谱的大型相亲交友婚恋平台有哪些?相亲app软件前十名

靠谱交友软件&#xff0c;个人感觉还是要选择大型的&#xff0c;口碑好的进行选择&#xff0c;以下是我用过的婚恋平台&#xff0c;分享给大家 1、丛丛 这是我用的最久的一款脱单小程序&#xff0c;我老公就是在这个小程序找到的&#xff01;&#xff01;&#xff01; 这是一款…

CF938Div3(A-F)

A: 买n个酸奶&#xff0c;一次一瓶a元,一次买两瓶可以优惠价b元,也可以a元,问恰好买n瓶需要多少钱. void solve() {int n, a, b;cin >> n >> a >> b;int ans min(a * n, n / 2 * b n % 2 * a);cout << ans << endl; } B: 给你一个数组,问能…

2024最新在线工具箱网站系统源码

2024最新在线工具箱网站系统源码 下载地址: 2024最新在线工具箱网站系统源码-JXASP源码网https://www.jxasp.com/think-php/12489.html