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

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

Java设计模式 - 解释器模式

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

java设计模式2.jpg

简介

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

解释器模式原理分析

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

主要角色与职责介绍

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

解释器模式实例

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

①、定义抽象解释器

抽象表达式类,定义一个抽象方法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)、变量解释器
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); // 获取值
    }
}

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;
    }
}

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); // 真正的运算,左边 + 右边,返回其和
    }
}

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); // 父类的父类 - 根据具体的某个对象去获取值来计算
    }
}

③、计算器

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

③、测试类

通过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;
    }
}

运行结果:
image.png

好,今天的分享就到这里。

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

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

💓德德小建议:

理解设计模式不是一件简单的事情,需要不断的学习和动手去练习,才能理解。只有掌握好设计模式,才能够真正的理解SpringAOP和Mybatis的底层原理。各位读者可以和我一样,动手敲一敲代码,甚至用不同的例子来做,通过debug一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️
相关文章
|
3天前
|
设计模式 前端开发 Java
19:Web开发模式与MVC设计模式-Java Web
19:Web开发模式与MVC设计模式-Java Web
12 4
|
3天前
|
设计模式 存储 前端开发
18:JavaBean简介及其在表单处理与DAO设计模式中的应用-Java Web
18:JavaBean简介及其在表单处理与DAO设计模式中的应用-Java Web
19 4
|
3天前
|
设计模式 缓存 监控
JAVA设计模式之结构型模式
结构模型:适配器模型、桥接模型、过滤器模型、组合模型、装饰器模型、外观模型、享受元模型和代理模型。
16 3
|
7天前
|
设计模式 算法 Java
Java基础教程(19)-设计模式简述
【4月更文挑战第19天】设计模式是软件设计中反复使用的代码设计经验,旨在提升代码的可重用性、可扩展性和可维护性。23种模式分为创建型、结构型和行为型三类。创建型模式如工厂方法、抽象工厂、建造者、原型和单例,关注对象创建与使用的分离。结构型模式涉及对象组合,如适配器、装饰器、外观等,增强结构灵活性。行为型模式专注于对象间职责分配和算法合作,包括责任链、命令、观察者等。设计模式提供标准化解决方案,促进代码交流和复用。
|
8天前
|
设计模式 Java
Java 设计模式:混合、装饰器与组合的编程实践
【4月更文挑战第27天】在面向对象编程中,混合(Mixins)、装饰器(Decorators)和组合(Composition)是三种强大的设计模式,用于增强和扩展类的功能。
13 1
|
8天前
|
设计模式 消息中间件 Java
Java 设计模式:探索发布-订阅模式的原理与应用
【4月更文挑战第27天】发布-订阅模式是一种消息传递范式,被广泛用于构建松散耦合的系统。在 Java 中,这种模式允许多个对象监听和响应感兴趣的事件。
24 2
|
8天前
|
设计模式 算法 Java
Java 设计模式:深入模板方法模式的原理与应用
【4月更文挑战第27天】模板方法模式是一种行为设计模式,主要用于定义一个操作中的算法的框架,允许子类在不改变算法结构的情况下重定义算法的某些特定步骤。
16 1
|
7月前
|
设计模式 安全 Java
JAVA设计模式1:单例模式,确保每个类只能有一个实例
JAVA设计模式1:单例模式,确保每个类只能有一个实例
|
8天前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
7月前
|
设计模式 存储 安全
【设计模式——学习笔记】23种设计模式——单例模式Singleton(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——单例模式Singleton(原理讲解+应用场景介绍+案例介绍+Java代码实现)
24 0