Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >21.设计模式--解释器模式(Interperter模式)

21.设计模式--解释器模式(Interperter模式)

作者头像
大猫的Java笔记
发布于 2021-11-19 08:15:22
发布于 2021-11-19 08:15:22
36900
代码可运行
举报
文章被收录于专栏:大猫的Java笔记大猫的Java笔记
运行总次数:0
代码可运行

1.定义

解释器模式是一种行为型模式,工作中基本上是用不到的,他的作用就是给定一个语言,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

现在有一个需求,大概就是计算器,首先给定一个公式,然后输入对应的值计算出最终的结果,公式不复杂,只能支持+和-操作。例如:输入a+b-c,100、200、100,然后计算结果为200。其中我们输入的a+b-c实际上可以理解为是另一种语言,那么此时就需要一个解释器进行语法解释,并计算结果。

现在需求有了我们分析一下公式中有哪些元素,其中有运算符以及参与运算的值,而对于解释器来说实际上只需要解释运算符以及参与运算的值即可,当然运算符可能又存在各种不同的运算符。例如加和减实际上对应的计算规则是不同的。

2.解释器模式结构图

VarExpression 用来解析运算的值,各个公式的运算元素的数量是不同的,每个运 算元素对应了一个 VarExpression 对象,SybmolExpression 是负责运算符号解析的,分别有两个子类 AddExpression(负责加法运算)和 SubExpression(负责减法运算)来实现。

Calculator类用于安排运算的先后顺序(加减法是不用考虑,但是乘除法呢?注意扩展性),并且还要返回结果,因此 我们需要增加一个封装类来处理进行封装,由于我们只作运算,暂时还不与业务有挂钩。

3.解释器模式实现

Expression抽象类,只是定义了一个方法interpreter方法用于进行计算,当然计算的逻辑由子类去实现,而参数HashMap中存放的key就是公式中的参数,例如a、b、c而value则代表的是对用的参数具体的值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class Expression {
    
    //解析公式和数值,其中var中的key值是是公式中的参数,如a、b、c,value值是具体的数字
    public abstract int interpreter(HashMap<String,Integer> var);
}

VarExpression是Expression的具体实现,用于解析公式中的具体运算值,如a、b、c具体对应的值是多少,当然具体的值就是通过key从HashMap中进行获取的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class VarExpression extends Expression {

    private String key;

    public VarExpression(String key) {
        this.key = key;
    }

    //从map中取之
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return var.get(this.key);
    }
}

SymbolExpression也是Expression的具体实现,用于解析公式运算符,当然对于运算符来说肯定需要知道左边是谁和右边是谁,不然怎么进行计算呢。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class SymbolExpression extends Expression {

    protected Expression left;

    protected Expression right;

    //所有的解析公式都应只关心自己左右两个表达式的结果
    public SymbolExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
}

AddExpression是具体的运算符解析器,是对SymbolExpression的具体实现,对于SymbolExpression来说只需要定义运算的左右两部分,而实际要加还是要减是子类来做的,所以AddExpression就是将左右两部分进行相加。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class AddExpression extends SymbolExpression {

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    //把左右两个表达式运算的结果加起来
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return left.interpreter(var) + right.interpreter(var);
    }
}

而是说SubExpression则是将运算符的左右部分做减法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SubExpression extends SymbolExpression {

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    //左右两个表达式相减
    @Override
    public int interpreter(HashMap<String, Integer> var) {
        return left.interpreter(var) - right.interpreter(var);
    }
}

Calculator构造函数接受一个表达式,然后把表达式转化为 char 数组, 并判断运算符号,如果是“+”则调用AddExpression,把左边的数(left 变量)和右边的数(right 变量)放入AddExpression。并且存放到Stack(栈)中。

那左边的数为什么是在堆栈中呢?原因是因为放入栈中是为了让计算有先后顺序,例如a+b-c,如果栈中已经有了a+b的AddExpression,那么如果再减法的时候应该是(a+b)作为左边,而c作为右边放入SubExpression。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Calculator {
    //定义的表达式
    private Expression expression;

    //构造函数传参,并解析
    public Calculator(String expStr) {
        //定义一个堆栈,安排运算的先后顺序
        Stack<Expression> stack = new Stack<Expression>();

        //表达式拆分为字符数组
        char[] charArray = expStr.toCharArray();

        //运算
        Expression left = null;
        Expression right = null;
        for (int i = 0; i < charArray.length; i++) {

            switch (charArray[i]) {
                case '+': //加法
                    //拿到加法的左边值,如a+b-c,拿到a
                    left = stack.pop();
                    //拿到加法的右边值,如a+b-c,拿到b
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    //将做加法的实体存入栈中
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                    //拿到减法的左边值,如a+b-c,拿到(a+b)
                    left = stack.pop();
                    //拿到减法的右边值,如a+b-c,拿到c
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    //将做减法的实体存入栈中
                    stack.push(new SubExpression(left, right));
                    break;
                default: //公式中的变量,即a或b或c
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
            }
        }

        //将需要计算的实体取出来,如a+b-c,则拿到(a+b)的实体和(a+b)-c的实体
        this.expression = stack.pop();
    }

    //开始运算
    public int run(HashMap<String, Integer> var) {
        return this.expression.interpreter(var);
    }
}

Test类来模拟用户情况,用户要求可以扩展,可以修改公式,那就通过接受键盘事件来处理,Client 类的源代码如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Test {
    //运行四则运算
    public static void main(String[] args) throws IOException {
        String expStr = getExpStr();
        //赋值
        HashMap<String,Integer> var = getValue(expStr);

        Calculator cal = new Calculator(expStr);
        System.out.println("运算结果为:"+expStr +"="+cal.run(var));
    }

    //获得表达式
    public static String getExpStr() throws IOException{
        System.out.print("请输入表达式:");
        return (new BufferedReader(new
                InputStreamReader(System.in))).readLine();
    }

    //获得值映射
    public static HashMap<String,Integer> getValue(String exprStr) throws
            IOException {
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        //解析有几个参数要传递
        for (char ch : exprStr.toCharArray()) {
            if (ch != '+' && ch != '-') {
                if (!map.containsKey(String.valueOf(ch))) { //解决重复参数的问题
                    System.out.print("请输入" + ch + "的值:");
                    String in = (new BufferedReader(new
                            InputStreamReader(System.in))).readLine();
                    map.put(String.valueOf(ch), Integer.valueOf(in));
                }
            }
        }

        return map;
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
请输入表达式:a+b-c
请输入a的值:100
请输入b的值:200
请输入c的值:20
运算结果为:a+b-c=280

解释器模式中的角色

AbstractExpression(抽象解释器),具体的解释任务由各个实现类完成。

concreteExpression(具体的解释器)具体的解释器分为两大类:TerminalExpression:终结符表达式,实现与文法中的元素相关联的解释操作,通常一个解释器模式 中只有一个终结符表达式,但有多个实例,对应不同的终结符。具体到我们例子就是 VarExpression 类, 表达式中的每个终结符都在堆栈中产生了一个 VarExpression 对象。 NonterminalExpression(非终结符表达式),文法中的每条规则对应一个非终结表达式,具体到我们的 例子就是加减法规则分别对应到 AddExpression 和 SubExpression 两个类。非终结符表达式根据逻辑的复 杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。 Context(环境角色),具体到我们的例子中是采用 HashMap 代替。

参考文献《设计模式之禅》

代码获取地址:https://gitee.com/bughong/design-pattern

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大猫的Java笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
设计模式——解释器模式
设计模式——解释器模式
Java架构师必看
2021/05/14
4140
设计模式——解释器模式
图解Java设计模式之解释器模式
通过解释器模式来实现四则运算,如计算 a + b + c 的值,具体要求 1)先输入表达式的形式,比如 a + b + c + d + e,要求表达式的字母不能重复 2)在分别输入a,b,c,d,e的值 3)最后求出结果
海仔
2020/04/08
1K0
图解Java设计模式之解释器模式
设计模式-解释器模式
具体做法是创建几个解释器,在创建一个解释器封装类,在解释器封装类中完成语法树的构建。然后在场景类中完成递归调用。
mySoul
2019/01/25
3780
解释器模式
@派大星
2023/06/28
1590
解释器模式
解释器模式-破解算术验证码
我头两年工作的时候,写过一些爬虫程序,爬取过京东的商品数据,今日影视的视频资源等等。有些资源是很容易爬的,只要发一个HTTP请求,无需任何处理服务端就会返回给你数据。但是对于一些比较珍贵的数据,服务端就会做「反爬虫」处理,我曾经在爬取第三方网站的文章时就遇到过,幸运的是人家的反爬虫机制比较简单:给出一个图片,图片里面是一个「算术题」,你必须输入算术题的正确答案,服务端才会响应文章的完整内容。算术题都是很简单的四则运算,小学生都会的那种,因此很容易破解。
全栈程序员站长
2022/09/05
7560
解释器模式-破解算术验证码
设计模式实战 - 解释器模式(Interpreter Pattern)
● 公式可以运行时编辑,并且符合正常算术书写方式,例如a+b-c ● 高扩展性,未来增加指数、开方、极限、求导等运算符号时较少改动 ● 效率可以不用考虑,晚间批量运算
JavaEdge
2018/12/17
9520
设计模式实战 - 解释器模式(Interpreter Pattern)
设计之禅——解释器模式(译文)
解释器模式在平时基本上用不到,因此笔者也不打算花太多精力在这上面,但强迫症使然,所以翻译了GeeksForGeeks上面的一篇文章,本文采取意译及注解方式,原文链接Interpreter Pattern
夜勿语
2020/09/07
3050
解释器模式 Interpreter 行为型 设计模式(十九)
如果形势变化非常多,这就不符合要求,因为加法和减法运算,两个运算符与数值可以有无穷种组合方式
noteless
2018/12/26
5630
设计模式----解释器模式
解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的 “语言” 是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
大忽悠爱学习
2021/11/15
9680
设计模式实战-解释器模式,今天给你解疑答惑
解释器模式,这个模式我觉得是这些模式中最不好理解的模式,解释器模式是用来干啥的呢?比如说我们有一段英文或者一段公式,我们需要知道其中表达的意思到底是啥?(假如我们起初并不理解)也就是说,我们需要一个"解释人",该角色就是我们的联络官或者叫做解释器,用来翻译我们的文本或者公式,翻译成我们能理解的最小的基础单元,听着是不是还云里雾里地?大家都知道编译器吧,一般的编译器分为词法分析器、语法分析器、语义分析器、中间代码优化器以及最终的代码生成器等,而我的理解,解释器就类似于其中的语法分析器的作用,专门负责语法文本的解析作用。
架构师修炼
2020/07/17
3000
设计模式21之解释器模式
在软件开发中,可能会出现某些相似的功能多次出现,这些功能有一定的相似性与规律性。这是我们就可以将其归纳成一种简单的语言。这就是解释器模式的来源。
Lvshen
2022/05/05
2280
设计模式21之解释器模式
【地铁上的设计模式】--行为型模式:解释器模式
解释器(Interpreter)是一种行为型设计模式,它用于解释一种特定的编程语言或表达式。它提供了一种解释一组语言语法的方法,使得用户可以按照特定的规则定义自己的语言,并通过解释器将其转化成可执行代码。 在解释器模式中,包含两个角色:终结符和非终结符。终结符表示语法规则中的基本单元,而非终结符表示由终结符组成的语法规则。解释器模式通常使用抽象语法树(Abstract Syntax Tree, AST)来实现对语法规则的解释。 解释器模式的优点在于它可以轻松地添加新的语法规则,同时保持代码的灵活性和可扩展性。它也能够在运行时动态生成代码,从而更好地支持动态编程。 然而,解释器模式的缺点在于它可能会导致性能问题,因为它需要在解释器中进行大量的运算和计算。此外,解释器模式的设计较为复杂,需要开发者具备较强的编程能力和领域知识。 在软件开发中,解释器模式通常应用于解析和执行脚本、编译器、数据库查询语言等场景。例如,JavaScript的解释器就是一种常见的解释器实现。
喵叔
2023/05/09
3090
设计模式之解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,用于定义语言的文法规则,并提供一个解释器来解释执行这些规则。它属于行为型模式,适用于需要解释语言语法或表达式的场景。
孟斯特
2024/02/06
820
设计模式之解释器模式
Java描述设计模式(14):解释器模式
一、解释器模式 1、基础概念 解释器模式是对象的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的表达式。 2、模式图
知了一笑
2019/10/18
5180
Java设计模式(二十三)----解释器模式
解释器模式 定义:解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。 解释器模式的结构 下
汤高
2018/01/11
5580
Java设计模式(二十三)----解释器模式
【设计模式】行为型模式-第 3 章第 3 讲【解释器模式】
 解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
跟着飞哥学编程
2022/12/02
3670
设计模式 | 解释器模式及典型应用
解释器模式(Interpreter Pattern):定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的 "语言" 是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
小旋锋
2019/01/21
8940
JAVA中的23种设计模式(GOF)
volatile 保证数据的可见性,让线程内存数据的变化立刻显示到主存中,而且有序性可以避免指令重排,但是不保证原子性。
HcodeBlogger
2020/08/05
9880
JAVA中的23种设计模式(GOF)
设计模式--解释器模式
解释器模式是一种行为型设计模式,它定义了一种语言解释器的方式,用于解释特定的语言或符号。在该模式中,定义一个语法,用于解释特定的输入,并把这个语法表示为一个解释器。
软件架构师Michael
2023/07/19
2900
设计模式(二十三):行为型之解释器模式
注意: 这里的符号“::=”表示“定义为”的意思,竖线 | 表示或,左右的其中一个,引号内为字符本身,引号外为语法
冬天vs不冷
2025/01/21
880
设计模式(二十三):行为型之解释器模式
相关推荐
设计模式——解释器模式
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档