文章目录
- 一、解释器模式简介
- 二、解释器模式适用场景
- 三、解释器模式优缺点
- 四、解释器模式与适配器模式
- 五、解释器模式代码示例
- 1、解释器接口
- 2、加法解释器
- 3、乘法解释器
- 4、整型解释器
- 5、语法解析类
- 6、工具类
- 7、测试类
一、解释器模式简介
解释器模式 : 给定一个 语言 , 定义它的 文法 的一种表示 , 并定义一个 解释器 , 这个 解释器 使用该表示来 解释 语言中的 句子 ;
文法 可以理解成一种 语法 ;
为了解释一种语言 , 而为语言创建的 解释器 ;
如 : Java 代码 , 需要编译器进行编译之后才能运行 , 这个编译器就相当于解释器 ;
解释器模式类型 : 行为型 ;
二、解释器模式适用场景
解释器模式适用场景 : 某个 特定类型问题 发生频率 足够高 ;
日志处理 : 使用 脚本语言 或 编程语言 处理日志时 , 有很多服务 会产生 大量的日志 , 需要 对日志进行解析 , 生成报表 ;
各个服务的日志格式不同 , 数据中的要素相同 , 这种情况下 , 通过程序解决上述问题 , 主要的解决方案就是使用解释器模式 ;
日常项目中 , 解释器模式使用情况很少 ;
解释器一般是 开源包 , 如 Express4J , JEP ;
三、解释器模式优缺点
解释器模式优点 : 语法 由 很多类 表示 , 容易 改变 及 扩展 " 语言 " ;
" 语言 " 用引号标注 , 这些语言不足以称为一门 编程语言 ;
解释器模式缺点 : 如果 语法规则 数目太多 , 会增加 系统 复杂度 ;
每个规则 都要与之对应 一个类 , 如果规则太多 , 则需要创建很多类 ;
解释器模式在实际业务中 , 是使用频率很低的设计模式 ;
四、解释器模式与适配器模式
解释器模式与适配器模式 : 这两个模式类似 , 但是略有不同 ;
- 适配器模式 : 不需要 预先知道 适配器的 规则 ;
- 解释器模式 : 需要 预先将规则写好 , 根据规则执行解释 ;
五、解释器模式代码示例
业务场景 :
输入字符串
代码语言:javascript复制10 2 3 *
将字符串使用空格切割成数组 遇到数字直接入栈 遇到运算符 , 从栈中取出两个数据 , 进行计算 , 将计算结果再放入栈中 遍历完毕后 , 最终的栈内数据就是最终结果
1、解释器接口
代码语言:javascript复制package interpreter;
/**
* 解释器接口
*/
public interface Interpreter {
/**
* 解释方法
* @return
*/
int interpret();
}
2、加法解释器
代码语言:javascript复制package interpreter;
/**
* 加法解释器
* 实现 Interpreter 解释器 接口
* 用于实现加法计算
* 加法有加数 和 被加数 , 两个加数分别也都是一个解释器
*/
public class AddInterpreter implements Interpreter {
/**
* 第一个表达式
*/
private Interpreter firstInterpreter;
/**
* 第二个表达式
*/
private Interpreter secondInterpreter;
public AddInterpreter(Interpreter firstInterpreter,
Interpreter secondInterpreter) {
this.firstInterpreter = firstInterpreter;
this.secondInterpreter = secondInterpreter;
}
@Override
public int interpret() {
return this.firstInterpreter.interpret()
this.secondInterpreter.interpret();
}
@Override
public String toString() {
return " ";
}
}
3、乘法解释器
代码语言:javascript复制package interpreter;
/**
* 乘法解释器
* 实现 Interpreter 解释器 接口
* 用于实现乘法计算
* 两个乘数分别也都是一个解释器
*/
public class MultiInterpreter implements Interpreter {
/**
* 第一个表达式
*/
private Interpreter firstInterpreter;
/**
* 第二个表达式
*/
private Interpreter secondInterpreter;
public MultiInterpreter(Interpreter firstInterpreter,
Interpreter secondInterpreter) {
this.firstInterpreter = firstInterpreter;
this.secondInterpreter = secondInterpreter;
}
@Override
public int interpret() {
return this.firstInterpreter.interpret() *
this.secondInterpreter.interpret();
}
@Override
public String toString() {
return "*";
}
}
4、整型解释器
代码语言:javascript复制package interpreter;
/**
* 数字解释器
* 实现 Interpreter 解释器 接口
*/
public class NumberInterpreter implements Interpreter {
/**
* 核心数字
* 需要将传入的数据转为数字
*/
private int number;
/**
* 直接设置数字类型
* @param number
*/
public NumberInterpreter(int number) {
this.number = number;
}
/**
* 将字符串转为数字类型
* @param number
*/
public NumberInterpreter(String number) {
this.number = Integer.parseInt(number);
}
@Override
public int interpret() {
return this.number;
}
@Override
public String toString() {
return "" this.number;
}
}
5、语法解析类
代码语言:javascript复制package interpreter;
import java.util.Stack;
/**
* 语法解析
*/
public class ExpressionParser {
/**
* 存放解释器的栈
* 栈的特点是先进后出
*/
private Stack<Interpreter> stack = new Stack<>();
/**
* 解析字符串语法
* @param str
*/
public void parse(String str) {
// 通过空格分割字符串
String[] strArray = str.split(" ");
// 遍历栈中的字符串
for (String symbol : strArray) {
if (!OperatorUtils.isOperator(symbol)) {
// 如果不是操作符 , 说明是数字 , 则直接入栈
Interpreter interpreter = new NumberInterpreter(symbol);
stack.push(interpreter);
System.out.println(symbol " 入栈");
} else {
// 如果是操作符 , 则数据出栈 , 处理是操作符运算的情况
// 取出两个需要计算的元素
Interpreter firstInterpreter = stack.pop();
System.out.println(firstInterpreter " 出栈");
Interpreter secondInterpreter = stack.pop();
System.out.println(secondInterpreter " 出栈");
// 获取 运算符号 对应的解释器
Interpreter operator = OperatorUtils.
getExpressionInterpretor(
symbol,
firstInterpreter,
secondInterpreter);
System.out.println("运算符 " operator " 出栈");
// 计算 运算符 运算结果
int result = operator.interpret();
// 将计算结果你年入栈
NumberInterpreter numberInterpreter = new NumberInterpreter(result);
stack.push(numberInterpreter);
System.out.println("计算结果 " result " 入栈");
}
}
// 取出最终计算结果 , 计算完毕后 , 整个栈必然只剩下一个元素
int result = stack.pop().interpret();
System.out.println("最终计算结果 : " result);
}
}
6、工具类
代码语言:javascript复制package interpreter;
public class OperatorUtils {
/**
* 判断传入的符号字符串是否是操作符
* @param symbol
* @return
*/
public static boolean isOperator(String symbol) {
return symbol.equals(" ") || symbol.equals("*");
}
public static Interpreter getExpressionInterpretor(
String symbol,
Interpreter firstInterpreter,
Interpreter secondInterpreter) {
Interpreter interpreter = null;
if (symbol.equals(" ")) {
interpreter = new AddInterpreter(firstInterpreter, secondInterpreter);
} else if (symbol.equals("*")) {
interpreter = new MultiInterpreter(firstInterpreter, secondInterpreter);
}
return interpreter;
}
}
7、测试类
代码语言:javascript复制package interpreter;
public class Main {
public static void main(String[] args) {
// 将字符串使用空格切割成数组
// 遇到数字直接入栈
// 遇到运算符 , 从栈中取出两个数据 , 进行计算 , 将计算结果再放入栈中
// 遍历完毕后 , 最终的栈内数据就是最终结果
String text = "10 2 3 *";
ExpressionParser parser = new ExpressionParser();
parser.parse(text);
}
}
执行结果 :
代码语言:javascript复制10 入栈
2 入栈
3 入栈
3 出栈
2 出栈
运算符 出栈
计算结果 5 入栈
5 出栈
10 出栈
运算符 * 出栈
计算结果 50 入栈
最终计算结果 : 50