Java 设计模式——解释器模式

目录

  • 1.概述
  • 2.结构
  • 3.案例实现
    • 3.1.抽象表达式类
    • 3.2.终结表达式
    • 3.3.非终结表达式
    • 3.4.环境类
    • 3.5.测试
  • 4.优缺点
  • 5.使用场景

1.概述

(1)如下图,设计一个软件用来进行加减计算。我们第一想法可能就是使用工具类,提供对应的加法和减法的工具方法。

在这里插入图片描述

//用于两个整数相加 
public static int add(int a,int b){ return a + b; 
}//用于两个整数相加 
public static int add(int a,int b,int c){ return a + b + c;
}//用于 n 个整数相加(使用可变参数)
public static int add(Integer... arr) { int sum = 0; for (Integer i : arr) { sum += i; }return sum; 
}

上面的形式比较单一、有限,如果形式变化非常多,这就不符合要求,因为加法和减法运算,两个运算符与数值可以有无限种组合方式。比如 1 + 2 + 3 + 4 + 5、1 + 2 + 3 - 4等等。显然,现在需要一种翻译识别机器,能够解析由数字以及 +、- 符号构成的合法的运算序列。如果把运算符和数字都看作节点的话,能够逐个节点的进行读取解析运算,这就是解释器模式的思维

(2)解释器模式 (Interpreter pattern) 是一种行为型设计模式,用于表示一个语言文法的语法规则,以及如何解析和执行该语法规则。解释器模式将一个语言表达式表示为对象,并定义了解析该表达式的语法规则。它包含了一个抽象表达式类和具体的表达式类。解释器模式主要通过使用递归来实现计算过程,即通过调用表达式对象的解释方法来进行计算。它可以用于编译器、解释器、数学公式计算等领域。

(3)在解释器模式中,我们需要将待解决的问题,提取出规则,抽象为一种“语言”。比如加减法运算,规则为:由数值和 +、- 符号组成的合法序列,“1 + 3 - 2” 就是这种语言的句子。解释器就是要解析出来语句的含义。但是如何描述规则呢?

(4)文法/语法规则(用于描述语言的语法结构的形式规则):

expression ::= value | plus | minus 
plus ::= expression '+' expression 
minus ::= expression '-' expression 
value ::= integer

注意: 这里的符号“::=”表示“定义为”的意思,竖线 | 表示或,左右的其中一个,引号内为字符本身,引号外为语法。上面规则描述为 :表达式可以是一个值,也可以是 plus 或者 minus 运算,而 plus 和 minus 又是由表达式结合运算符构成,值的类型为整型数。

(5)抽象语法树
在计算机科学中,抽象语法树 (Abstract Syntax Tree,AST),或简称语法树 (Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。用树形来表示符合文法规则的句子:
在这里插入图片描述

2.结构

解释器模式包含以下主要角色:

  • 抽象表达式 (Abstract Expression) 角色:定义了一个抽象的接口,用于解析语法规则。通常它是一个抽象类或接口,其中包含了解释器需要实现的方法。。
  • 终结符表达式 (Terminal Expression) 角色:终结符表达式是最基本的表达式,它代表语言中的一个基本单元,通常是一个具体的值或一个变量。
  • 非终结符表达式 (Nonterminal Expression) 角色:非终结符表达式是由多个终结符表达式或其他非终结符表达式组成的复合表达式。
  • 环境 (Context) 角色:环境对象包含了解析器运行所需要的全局信息。
  • 客户端 (Client) 角色:客户端用于创建解释器并调用其解释方法来解析语法规则。

3.案例实现

【例】设计实现加减法的软件
在这里插入图片描述
具体实现代码如下:

3.1.抽象表达式类

AbstractExpression.java

//抽象表达式类
public abstract class AbstractExpression {public abstract int interpret(Context context);
}

3.2.终结表达式

Variable.java

//用于封装变量的类
public class Variable extends AbstractExpression{//声明存储变量名的成员变量private String name;public Variable(String name) {this.name = name;}@Overridepublic int interpret(Context context) {//直接返回变量的值return context.getValue(this);}@Overridepublic String toString() {return name;}
}

3.3.非终结表达式

Plus.java

//加法表达式类
public class Plus extends AbstractExpression{// + 左边的表达式private AbstractExpression left;// + 右边的表达式private AbstractExpression right;public Plus(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {//将左边表达式的结果和右边的进行相加return left.interpret(context) + right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + "+" + right.toString() + ")";}
}

Minus.java

//减法表达式类
public class Minus extends AbstractExpression{// - 左边的表达式private AbstractExpression left;// - 右边的表达式private AbstractExpression right;public Minus(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {//将左边表达式的结果和右边的进行相减return left.interpret(context) - right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + "-" + right.toString() + ")";}
}

3.4.环境类

Context.java

//环境角色类
public class Context {//定义一个 map 集合,用来存储变量以及对应的值private Map<Variable,Integer> map = new HashMap<>();//添加变量的功能public void assign(Variable var, Integer value){map.put(var, value);}//根据变量获取对应的值public int getValue(Variable var){return map.get(var);}
}

3.5.测试

Client.java

public class Client {public static void main(String[] args){//创建环境对象Context context = new Context();//创建多个变量对象Variable a = new Variable("a");Variable b = new Variable("b");Variable c = new Variable("c");Variable d = new Variable("d");//将变量存储到环境变量中context.assign(a, 1);context.assign(b, 2);context.assign(c, 3);context.assign(d, 4);//获取抽象语法树  a + b - c + dAbstractExpression expression = new Minus(a, new Plus(new Minus(b, c), d));//解释,即计算int result = expression.interpret(context);System.out.println(expression + "=" + result);}
}

结果如下:

(a-((b-c)+d))=-2

4.优缺点

(1)解释器模式的主要优点是:

  • 灵活性:解释器模式可以根据需要动态地修改解释器的表达式,从而扩展或修改语言。
  • 易于扩展:新的解释器可以通过扩展抽象语法树节点类来轻松添加到系统中。
  • 可重用性:同样的解释器可以在不同的环境下重用,只需要修改解释器的上下文即可。
  • 独立性:解释器模式使得解释器与其它部分相互独立,修改解释器不会影响其他部分的功能。

(2)解释器模式的主要缺点是:

  • 复杂性:因为解释器模式涉及到抽象语法树、终结符和非终结符等概念,因此实现起来比较复杂。
  • 效率问题:由于解释器模式使用递归调用的方式进行解释处理,因此对于复杂的语法和大量的数据处理,可能会导致效率问题。

5.使用场景

(1)解释器模式适用于以下场景:

  • 当有一个简单的语法规则,并且需要频繁地对该语法进行解释和执行时,可以考虑使用解释器模式。
  • 当需要将一个语言或规则进行扩展或修改时,解释器模式可以提供灵活的扩展性和易于修改的特性。
  • 当语法规则相对稳定,但需要根据不同的上下文进行不同的解释时,可以使用解释器模式。
  • 当需要解耦语法规则的解释过程与具体的操作时,解释器模式可以将语法解释与操作分离,从而提高代码的可维护性和可扩展性。
  • 当需要构建一个能够解释执行特定领域语言的工具或引擎时,解释器模式是一种常用的设计模式。

(2)总之,解释器模式适用于需要解释和执行简单语法规则、动态扩展语言等场景,可以提供灵活性、可扩展性和可维护性。

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

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

相关文章

算法打卡01——求两数之和

题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你…

机器学习 - DBSCAN聚类算法:技术与实战全解析

目录 一、简介DBSCAN算法的定义和背景聚类的重要性和应用领域DBSCAN与其他聚类算法的比较 二、理论基础密度的概念核心点、边界点和噪声点DBSCAN算法流程邻域的查询聚类的形成过程 参数选择的影响 三、算法参数eps&#xff08;邻域半径&#xff09;举例说明&#xff1a;如何选择…

Android工具栏ToolBar

主流APP除了底部有一排标签栏外&#xff0c;通常顶部还有一排导航栏。在Android5.0之前&#xff0c;这个顶部导航栏以ActionBar控件的形式出现&#xff0c;但AcionBar存在不灵活、难以扩展等毛病&#xff0c;所以Android5.0之后推出了ToolBar工具栏控件&#xff0c;意在取代Aci…

2023年11月5日网规考试备忘

早上题目回忆&#xff1a; pki体系 ipsec&#xff0c;交换安全&#xff08;流量抑制&#xff09; aohdlc bob metclaf —ethernet pon tcp三次握手 OSPF lsa&#xff1f;交换机组ospf配置问题&#xff0c;ping网关可通&#xff0c;AB不通 raid6 300G*8 网络利用率 停等协议10…

解决docker tag打标签时报错:Error response from daemon: no such id

现象&#xff1a; 原因&#xff1a; docker tag时不仅仅要Repository仓库名&#xff0c;也需要原有的tag作为版本号 解决办法&#xff1a; docker tag 原有仓库名: 原有tag值 新的打标名称 问题解决&#xff01;

关于卷积神经网络的多通道

多通道输入 当输入的数据包含多个通道时&#xff0c;我们需要构造一个与输入通道数相同通道数的卷积核&#xff0c;从而能够和输入数据做卷积运算。 假设输入的形状为n∗n&#xff0c;通道数为ci​&#xff0c;卷积核的形状为f∗f&#xff0c;此时&#xff0c;每一个输入通道都…

陈海波:OpenHarmony技术领先,产学研深度协同,生态蓬勃发展

11月4日&#xff0c;以“技术筑生态&#xff0c;智联赢未来”为主题的第二届OpenHarmony技术大会在北京隆重举办。本次大会由OpenAtom OpenHarmony&#xff08;简称“OpenHarmony"&#xff09;项目群技术指导委员会&#xff08;TSC&#xff09;主办&#xff0c;由华为技术…

Steam余额红锁的原因,及红锁后申诉方法

CSGO饰品自动上架助手使用教程 安全的余额一般是通过充值卡充值获得&#xff0c;再加上交易手续费再转卖给你。一般便宜不到哪去。 但你别以为余额是安全的&#xff0c;就万事大吉了。照样有被红锁的可能性&#xff0c;比如这三种&#xff1a; 1、Steam市场巡查机制&#xff…

基于卷积优化算法的无人机航迹规划-附代码

基于卷积优化算法的无人机航迹规划 文章目录 基于卷积优化算法的无人机航迹规划1.卷积优化搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用卷积优化算法来优化无人机航迹规划。 …

220v插座led指示灯维修

由于220v是交流电&#xff0c;有反向电压的情况&#xff0c;而led反向通电的时候电阻无穷大&#xff0c;所以分压也无穷大&#xff0c;220v一导通就击穿&#xff0c;即使加了很大的电阻也没用&#xff0c;串联电阻只能作用于二极管正向的时候。 目前有两种方案&#xff1a; 方…

C语言实现利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示

完整代码&#xff1a; /*利用条件运算符的嵌套来完成此题&#xff1a;学习成绩>90分的同学用A表示&#xff0c;60-89分之间 的用B表示&#xff0c;60分以下的用C表示*/ #include<stdio.h>int main(){int score;char grade;printf("请输入你的成绩&#xff1a;&q…

【Linux】:文件系统

文件系统 一.认识硬件-磁盘1.磁盘的物理构成2.磁盘的存储构成3.逻辑结构 二.文件系统 文件内容属性&#xff0c;前面我们所说的文件操作都是针对以打开的文件&#xff0c;那么未打开的文件呢&#xff1f;当然是在磁盘上储存着&#xff0c;接下来谈谈它是如何储存的。 一.认识硬…