• 【设计模式】Java设计模式 - 解释器模式


    Java设计模式 - 解释器模式

    😄 不断学习才是王道
    🔥 继续踏上学习之路,学之分享笔记
    👊 总有一天我也能像各位大佬一样
    🏆 一个有梦有戏的人 @怒放吧德德
    🌝分享学习心得,欢迎指正,大家一起学习成长!

    封面图

    简介

    解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

    解释器模式原理分析

    解释器模式就是给定一个表达式,定义他的文法表示,并且定义一个解释器,使用这个解释器来解释语言中的表达式。比较灵活,也比较容易拓展。
    解释器模式比较不常见,一般应用于编译器、SQL解析、表达式计算。
    原理UML图:
    UML

    主要角色与职责介绍

    Expression:解释器(表达式),声明一个抽象的解释操作,由具体的解释器继承实现,这个方法是抽象语法树中所有结点共享。
    TerminalExpression:终结符表达式,实现文法中与终结符相关的解释操作
    NoTerminalExpression:非终结符表达式,实现文法中与非终结符相关的解释操作

    解释器模式实例

    本次实验采用解释器模式来解决算数计算,输入运算表达式,通过具体的解释器模式去得出结果,本次只是使用了简单的加减法计算,如果需要扩展乘法除法、括号,就要考虑计算先后顺序,通过栈来实现。
    本次类图:
    类图

    ①、定义抽象解释器

    抽象表达式类,定义一个抽象方法interpreter给子类(具体的解释器)来实现,目的是获取其值。

    package com.lyd.demo.interpreter;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 抽象类表达式,通过HashMap 键值对, 可以获取到变量的值
     * @Date: 2022-09-10
     */
    public abstract class Expression {
        /**
         * 解释公式和数值, key 就是公式(表达式) 参数[a,b,c], value就是具体值
         * @param var 存储数据
         * @return
         */
        public abstract int interpreter(HashMap<String, Integer> var);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ②、具体的解释器

    1)、变量解释器
    key是表达式变量名,通过key来获取相应表达式中变量的值。

    package com.lyd.demo.interpreter.var;
    import com.lyd.demo.interpreter.Expression;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 变量解释器
     * @Date: 2022-09-10
     */
    public class VarExpression extends Expression {
        // 表示键值对的键
        private String key;
        // 构造器初始化
        public VarExpression(String key) {
            this.key = key;
        }
        @Override
        public int interpreter(HashMap<String, Integer> var) {
            return var.get(this.key); // 获取值
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2)、抽象运算符号解析器
    因为四则运算有四种符号,每种符号有各自的操作,并且符号对数字的操作跟自己左右的数字有关系,需要对左右的变量的操作,并且这些都有一个共同父类-Expression,故在实例化运算符解释器的时候,需要传入左右的变量,并且赋值,在有具体的子类(具体运算符解释器)来做具体的操作,并且返回计算的值。

    package com.lyd.demo.interpreter.symbol;
    import com.lyd.demo.interpreter.Expression;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 抽象运算符号解析器 - 每个运算符号,都只和自己左右两个数字有关系,
     * @Date: 2022-09-10
     */
    public class SymbolExpression extends Expression {
        public Expression left;
        public Expression right;
        public SymbolExpression(Expression left, Expression right) {
            this.left = left;
            this.right = right;
        }
        // 因为有许多的符号,interpreter用子类在实现
        @Override
        public int interpreter(HashMap<String, Integer> var) {
            return 0;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2-1)、加法解释器
    interpreter方法里面做具体的对应计算,传入的hashMap是变量值,从而获得计算的值。

    package com.lyd.demo.interpreter.symbol;
    import com.lyd.demo.interpreter.Expression;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 具体的运算符解释器 - 加法解释器
     * @Date: 2022-09-10
     */
    public class AddExpression extends SymbolExpression{
        public AddExpression(Expression left, Expression right) {
            super(left, right);
        }
        /**
         * 子类才是真正的实现
         * @param var
         * @return
         */
        @Override
        public int interpreter(HashMap<String, Integer> var) {
            return super.left.interpreter(var) + super.right.interpreter(var); // 真正的运算,左边 + 右边,返回其和
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2-2)、减法解释器

    同加法解释器,只是把加号换成了减号。

    package com.lyd.demo.interpreter.symbol;
    import com.lyd.demo.interpreter.Expression;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 具体的运算符解释器 - 减法解释器
     * @Date: 2022-09-10
     */
    public class SubExpression extends SymbolExpression{
        public SubExpression(Expression left, Expression right) {
            super(left, right);
        }
        @Override
        public int interpreter(HashMap<String, Integer> var) {
            return super.left.interpreter(var) - super.right.interpreter(var); // 父类的父类 - 根据具体的某个对象去获取值来计算
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ③、计算器

    根据表达式调用解释器来完成结果计算。计算四则运算,通过栈来实现,实现的是从左往右计算,但未涉及乘除、括号的优先级计算(读者可以自己进行扩展,主要扩展是实现运算符解释器以及通过栈做好优先级计算)。通过传来的字符串将其转成字符数组,通过遍历这些字符进行处理,遇到变量(数字)的时候,将其实例化成变量解释器存到栈中,在遇到符号的时候,通过获取上一个变量解释器,以及获取下一个数字并实例化成变量解释器,在实例化具体的运算符解释器并存入栈中,最后定义run方法执行解释器类的interpreter方法。

    package com.lyd.demo.interpreter.calculator;
    import com.lyd.demo.interpreter.Expression;
    import com.lyd.demo.interpreter.symbol.AddExpression;
    import com.lyd.demo.interpreter.symbol.SubExpression;
    import com.lyd.demo.interpreter.var.VarExpression;
    import java.util.HashMap;
    import java.util.Stack;
    /**
     * @Author: lyd
     * @Description: 计算器
     * @Date: 2022-09-10
     */
    public class Calculator {
        // 定义表达式 - 抽象类表达式
        private Expression expression;
        // 构造函数传参,并解析
        public Calculator(String expStr) { // 传来的运算字符串
            // 用栈来实现计算顺序
            Stack<Expression> stack = new Stack<Expression>();
            // 表达式装成数组
            char[] chars = expStr.toCharArray();
            // 定义左右
            Expression left = null;
            Expression right = null;
            // 遍历,进行处理
            for (int i=0; i<chars.length; i++) {
                switch (chars[i]) {
                    case '+' : // 加法运算
                        left = stack.pop(); // 取出值,并且在stack栈中去除(peek是瞄一下,只拿值,不删除)
                        right = new VarExpression(String.valueOf(chars[++i]));
                        stack.push(new AddExpression(left, right));// 然后根据得到left 和 right 构建 AddExpresson加入stack
                        break;
                    case '-' : // 减法
                        left = stack.pop(); // 取出值,并且在stack栈中去除(peek是瞄一下,只拿值,不删除)
                        right = new VarExpression(String.valueOf(chars[++i]));
                        stack.push(new SubExpression(left, right));// 然后根据得到left 和 right 构建 AddExpresson加入stack
                        break;
                    default:
                        // 如果是数值,直接存进去
                        stack.push(new VarExpression(String.valueOf(chars[i])));
                        break;
                }
            }
            // 便利完毕后,栈中会存放最后一个Expression
            this.expression = stack.pop();
        }
        public int run(HashMap<String, Integer> var) {
            // 传递给expression的interpreter进行解释执行
            return this.expression.interpreter(var);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    ③、测试类

    通过Calculator类去实现计算。getExpStr输入表达式,getValue是将传入的表达式进行拆分,在不是运算符的时候,将其变量字符作为map的key提示用户输入数字,存储表达式所对应的数值。

    package com.lyd.demo.test;
    import com.lyd.demo.interpreter.calculator.Calculator;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.HashMap;
    /**
     * @Author: lyd
     * @Description: 测试类
     * @Date: 2022-09-10
     */
    public class InterpreterTest {
        public static void main(String[] args) throws IOException {
            String expStr = getExpStr(); // a+b
            HashMap<String, Integer> var = getValue(expStr);// var {a=10, b=20}
            Calculator calculator = new Calculator(expStr);
            System.out.println("运算结果:" + expStr + "=" + calculator.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 expStr) throws IOException {
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            for (char ch : expStr.toCharArray()) {
                if (ch != '+' && ch != '-') {
                    if (!map.containsKey(String.valueOf(ch))) {
                        System.out.print("请输入" + String.valueOf(ch) + "的值:");
                        String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
                        map.put(String.valueOf(ch), Integer.valueOf(in));
                    }
                }
            }
            return map;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    运行结果:
    结果图
    好,今天的分享就到这里。

    👍创作不易,可能有些语言不是很通畅,如有错误请指正,感谢观看!记得一键三连哦!👍

    根据以前编写的文章,慢慢查找不足点,一步一步进步,逐渐学习写出更好的文章。

    💓德德小建议:

    理解设计模式不是一件简单的事情,需要不断的学习和动手去练习,才能理解。只有掌握好设计模式,才能够真正的理解SpringAOP和Mybatis的底层原理。各位读者可以和我一样,动手敲一敲代码,甚至用不同的例子来做,通过debug一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️

  • 相关阅读:
    【C++】类
    234.回文链表
    开源在线表单工具 HeyForm 使用教程
    「Verilog学习笔记」优先编码器电路①
    SpringBoot_RestTemplate使用总结
    增益与功率:lg|dB|dBm|mW计算
    计算机视觉——基本矩阵的计算
    MySql查询慢-如何提高查询速度呢?--解决方法
    Nuxt - Universal(SSR / SSG)/ Single Page App(渲染模式)
    中英文说明书丨艾美捷T7 RNA聚合酶介绍
  • 原文地址:https://blog.csdn.net/qq_43843951/article/details/126806319