浅谈Java解释器模式
作者:KnightHONG 发布时间:2021-08-23 23:45:59
**请注意!请注意!!!**今天讲给大家讲解非常“有用”的设计模式,解释器模式!!!
设计模式有三大种类,一种是创建型模式,一种是结构型模式,最后一种是行为性模式,那么解释器模式属于哪一种呢?带领大家一起来了解学习解释器模式!
本次介绍围绕着以下五点展开。什么是解释器模式?用来做什么?怎么做?有哪些优点?有哪些不足?
解释器模式顾名思义,就是用来定义和解释。
给定一种特定语言,这个语言有特定的文法,解释器可以解释这个语言中的句子含义。即解释器提供一种语言,如java,同时它也提供一种手段去解析java语言写出来的代码。
大家可能也会想到这就是类似编译原理,一个算术表达式要经过词法分析,语法分析,构建语法树啥的;还有正则表达式;SQL解析,编译器等等,其实都是解析式模式的一种实现。
那怎么做?一个是说要有像编译原理中的终结符和非终结符,构建一颗语法树。同时需要有一个环境类,来管理输入和输出。
这里我们举一个例子,输入一个表达式a+b-c+d-e,同时给这5个变量赋值,计算出它的值。那么使用解释器模式要如何实现?
我们为解释器定义一个抽象解释类Expression,所有的流转通过interpreter方法实现。
上下文管理输入输出使用一个HashMap
去实现。
定义符号解释类SymbolExpression
,加法解释类AddExpreesion
,减法解释类SubExpression
。
类图:
具体代码实现:
public abstract class Expression {
// map中携带了表达式中的变量名(key) 和 对应的值(value)
public abstract int interpreter(Map<String, Integer> var);
}
public class VarExpression extends Expression {
// 表达式中对应的变量名
String key;
public VarExpression(String var) {
this.key = var;
}
@Override
public int interpreter(Map<String, Integer> var) {
return var.get(key);
}
}
public class SymbolExpression extends Expression {
// +或-符号 左右两边的表达式
Expression var1;
Expression var2;
public SymbolExpression(Expression var1, Expression var2) {
this.var1 = var1;
this.var2 = var2;
}
@Override
public int interpreter(Map<String, Integer> var) {
// 实现抽象方法
// 该类不需要用到该方法 默认返回0
return 0;
}
}
public class AddExpression extends SymbolExpression {
public AddExpression(Expression var1, Expression var2) {
super(var1, var2);
}
@Override
public int interpreter(Map<String, Integer> var) {
return var1.interpreter(var) + var2.interpreter(var);
}
}
public class SubExpression extends SymbolExpression {
public SubExpression(Expression var1, Expression var2) {
super(var1, var2);
}
@Override
public int interpreter(Map<String, Integer> var) {
return var1.interpreter(var) - var2.interpreter(var);
}
}
public class Calculator {
// 表达式
private Expression expression;
// 解析出表达式
public Calculator(String expStr) {
Stack<Expression> stack = new Stack<>();
Expression left, right = null;
char[] expStrCharArray = expStr.toCharArray();
for(int i = 0; i < expStrCharArray.length; i++) {
switch (expStrCharArray[i]) {
case '+':// 加法运算 获取左边表达式 右边数值
left = stack.pop();
right = new VarExpression(String.valueOf(expStrCharArray[++i]));
stack.push(new AddExpression(left, right));
break;
case '-':// 减法运算 获取左边表达式 右边数值
left = stack.pop();
right = new VarExpression(String.valueOf(expStrCharArray[++i]));
stack.push(new SubExpression(left, right));
break;
default:// 表达式中的变量
stack.push(new VarExpression(String.valueOf(expStrCharArray[i])));
break;
}
}
// 最后会获得被Expression包装起来的一个表达式
this.expression = stack.pop();
}
// 计算结果
public int run(Map<String, Integer> var) {
return this.expression.interpreter(var);
}
}
public class Client {
public static void main(String[] args) throws IOException {
String expStr = getExpStr();
Map<String, Integer> var = getValue(expStr);
Calculator calculator = new Calculator(expStr);
System.out.println("运算结果:" + expStr + "=" + calculator.run(var));
}
//获得表达式
public static String getExpStr() {
return "a+b-c+d-e";
}
//获得值映射
public static HashMap<String, Integer> getValue(String expStr) throws IOException {
HashMap<String, Integer> map = new HashMap<>();
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;
}
}
结果
/*
请输入a的值:1
请输入b的值:3
请输入c的值:5
请输入d的值:7
请输入e的值:9
运算结果:a+b-c+d-e=-3
*/
或许看代码会有点云里雾里,希望大家能手动敲一遍,或许会对整个过程有更进一步的理解,在编码的同时不断思考,提升自我。
很容易发现解释器模式是属于行为性模式的一种,这种模式更关注对象之间的通信。
解释器模式优点,结构清晰,可拓展性好。但也有缺点,一般用在比较底层场景,平常敲代码可使用的场景比较少,并且解释器模式采用的是递归的方式,当语言比较长,性能不高;同时如果文法比较复杂,也需要更多的相应解释类。
来源:https://blog.csdn.net/KnightHONG/article/details/120693753


猜你喜欢
- 经典的排序算法有八种,分别为:冒泡排序选择排序插入排序归并排序希尔排序快速排序堆排序基数排序其中冒泡排序、选择排序、插入排序称为三大基本排序
- maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略:<dependency> &
- SpringBoot访问外部文件及默认路由1 新增配置类package com.pibigstar.common.config;import
- 一、概述在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义
- 本文实例讲述了java方法重写,分享给大家供大家参考。具体分析如下:一、方法的重写概述:1、在子类中可以根据需要对从基类中继承来的方法进行重
- 配置Thymeleaf的模板路径众所周知,Thymeleaf的模板文件默认是在项目文件夹的src\main\resources\templa
- 昨天写了一个关于Excel文件处理的脚本,在字符串匹配功能上总是出现多余不正确的匹配,debug调试之后,发现一个坑。------->
- ThreadLocal 看名字 就可以看出一点头绪来,线程本地。来看一下java对他的描述:该类提供线程本地变量。这些变量与它们的正常对应变
- 前言最近项目需要和Oracle数据库进行交互,然后我从Maven中央仓库下载数据库驱动jar包,但怎么都下不下来,我到Oracle官网上一看
- 在TextView中添加文本时有时会改变一些文本字体的颜色,今天主要分享三种实现方法及相关优缺点。1、通过html标签改变文本颜色tv.se
- 上一章说明了DataBinding生存的类之间关系,现在这里来看看布局是如何加载的以及view是如何映射的。一、布局加载这里把之前的代码重新
- 本文实例为大家分享了C语言实现学生成绩管理系统的具体代码,供大家参考,具体内容如下结构体版的学生成绩管理系统主要功能有按1 输入学生信息按2
- 验证用户是否已经登录package cn.hongxin.filter;import java.io.IOException;import
- 什么是ApplicationContext?它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些。 App
- android动态布局相比静态布局,动态布局不用再将xml转变了布局代码,提高了一定的效率,当然可以忽略不记。动态布局主要是比较灵活,可以很
- 本文实例讲述了C#监控文件夹变化的方法。分享给大家供大家参考。具体实现方法如下:当需要监控某一文件,FileSystemWatcher类提供
- Android中Uri和Path之间的转换原因调用系统拍照应用,拍照后要保存图片,那么我们需要指定一个存储图片路径的Uri。这就涉及到如何将
- 先引用using System.Runtime.InteropServices; 的命名空间, 然后在合适的位置加上如下代码就OK。。注意:
- 需求是在我按下按钮时,该变按钮颜色,使用户感觉到自己按了按钮,当松开的时候,变回原来的颜色。正常时:按下时:有人说,直接监听按钮的按下事件不
- 背景接上文《失踪人口回归,mybatis-plus 3.3.2 发布》[1] ,提供了一个非常实用的功能 「数据安全保护」 功能,不仅支持数