【设计模式】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一步一步调试,还有就是多看看别人的例子。能够有助于理解!谢谢各位观看指点!❤️ ❤️ ❤️
相关文章
|
22天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
1月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
36 4
|
2月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
52 0
[Java]23种设计模式
|
1月前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
2月前
|
设计模式 监控 算法
Java设计模式梳理:行为型模式(策略,观察者等)
本文详细介绍了Java设计模式中的行为型模式,包括策略模式、观察者模式、责任链模式、模板方法模式和状态模式。通过具体示例代码,深入浅出地讲解了每种模式的应用场景与实现方式。例如,策略模式通过定义一系列算法让客户端在运行时选择所需算法;观察者模式则让多个观察者对象同时监听某一个主题对象,实现松耦合的消息传递机制。此外,还探讨了这些模式与实际开发中的联系,帮助读者更好地理解和应用设计模式,提升代码质量。
Java设计模式梳理:行为型模式(策略,观察者等)
|
2月前
|
设计模式 Java
Java设计模式
Java设计模式
33 0
|
2月前
|
设计模式 Java
Java设计模式之外观模式
这篇文章详细解释了Java设计模式之外观模式的原理及其应用场景,并通过具体代码示例展示了如何通过外观模式简化子系统的使用。
35 0
|
6月前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
72 4
|
3月前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
45 11
|
4月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
下一篇
DataWorks