目录
什么是解释器模式
解释器模式的实现
解释器模式角色
解释器模式类图
解释器模式举例
解释器模式代码实现
解释器模式的特点
优点
缺点
使用场景
注意事项
实际应用
什么是解释器模式
解释器模式(Interpreter Pattern)属于行为型模式,其提供了评估语言的语法或表达式的方式。给定一个语言,解释器模式可以定义出其文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。解释器中涉及到的文法,就是符合一定规则的语句结构.其实质是把语言中的每个符号定义成一个(对象)类,从而把每个程序转换成一个具体的对象树。
解释器模式的实现
解释器模式角色
环境角色(Context):用来存储解释器的上下文环境,包含解释器之外的一些全局信息,比如需要解释的文法等。
解释器抽象类角色(Abstract Expression):定义解释器的接口,声明一个所有的具体表达式角色都需要实现的抽象接口,约定解释器的解释操作。
终结符表达式角色(Terminal Expression):解释器具体实现类,实现了抽象表达式角色所要求的接口,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。通常在一个解释器模式中只有少数个终结符表达式,其实例可以通过非终结符表达式组成较为复杂的句子。
非终结符表达式角色(Nonterminal Expression):解释器具体实现类,,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。其非终结符表达式中即可包含终结符表达式,也可继续包含非终结符表达式,因此解释操作一般通过递归的方式来完成。
解释器模式类图
解释器模式举例
比如我们要定义一个“+”,“-”的操作,通过表达式角色中的解释器来完事具体的加减操作。
解释器模式代码实现
环境角色
package com.common.demo.pattern.interpreter;
import java.util.HashMap;
import java.util.Map;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 环境角色
* @date 2023/08/02 21:20:30
*/
public class Context {
//存储变量及对应的值
private Map<VariableExpression,Integer> map = new HashMap<>();
//添加变量
public void addVar(VariableExpression variable, Integer value){
map.put(variable,value);
}
//根据变量获取对应的值
public int getValue(VariableExpression variable){
return map.get(variable);
}
}
解释器抽象角色
package com.common.demo.pattern.interpreter;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 抽象表达式
* @date 2023/08/02 21:28:04
*/
public interface Expression {
int interpret(Context context);
}
终结表达式角色
package com.common.demo.pattern.interpreter;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 终结表达式角色:加减的数据变量
* @date 2023/08/02 21:30:06
*/
public class VariableExpression implements Expression {
/**
* 声明存储的变量名
*/
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public int interpret(Context context) {
return context.getValue(this);
}
@Override
public String toString() {
return name;
}
}
非终结表达式角色
package com.common.demo.pattern.interpreter;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 非终结表达式角色:减法
* @date 2023/08/02 21:33:49
*/
public class MinusExpression implements Expression{
//左边表达式 变量
private Expression left;
//右边表达式 变量
private Expression right;
public MinusExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
//返回左边的值 - 右边的值
return left.interpret(context)-right.interpret(context);
}
}
package com.common.demo.pattern.interpreter;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 非终结表达式角色:加法
* @date 2023/08/02 21:33:00
*/
public class PlusExpression implements Expression {
//左边表达式 变量
private Expression left;
//右边表达式 变量
private Expression right;
public PlusExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
//返回左边的值 + 右边的值
return left.interpret(context) + right.interpret(context);
}
}
测试代码
package com.common.demo.pattern.interpreter;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc
* @date 2023/08/02 21:35:29
*/
public class ClientTest {
public static void main(String[] args) {
//定义环境类
Context context = new Context();
//定义变量
VariableExpression a = new VariableExpression("a");
VariableExpression b = new VariableExpression("b");
VariableExpression c = new VariableExpression("c");
//将变量添加到环境类
context.addVar(a,13);
context.addVar(b,2);
context.addVar(c,3);
//运算 a+b-c 即13+2-3
Expression expression = new PlusExpression(a,new MinusExpression(b,c));
//结果
int res = expression.interpret(context);
System.out.println("结果为:"+res);
}
}
测试截图
解释器模式的特点
优点
- 可扩展性强:可以通过扩展语言中的表达式和语法规则来实现新的行为,可以通过继承机制来改变和扩展文法。
- 易于实现文法:解释器模式实现相对简单,只需要实现抽象表达式和具体表达式类即可,而定义抽象语法树中各个节点地类的实现大体类似。
- 易于拓展语法规则:解释器模式可以让用户较为方便的增加新类型的表达式,增加新的表达式时无需对现有的表达式进行修改,符合开闭原则。
缺点
- 执行效率较低:解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
- 会引起类膨胀:解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
- 可应用的场景比较少:在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
- 复杂的文法比较难维护:对于复杂文法难以维护,其每一条规则至少需要定义一个类,若一个语言包含太多文法规则,则可能难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
使用场景
- 当语言的文法较为简单,且执行效率、性能要求不高。
- 当问题重复出现,相似的处理逻辑,可抽象为一种简单语言,且可以用一种简单的语言来进行表达时。
- 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如XML文档解释。
注意事项
- 尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目中可以使用shell,JRuby,Groovy等脚本语言来代替解释器模式,弥补Java编译型语言的不足。
- 对执行效率、性能要求时,不要使用解释器模式
- 复杂的文法,解释器模式中的文法类层次结构将变得很庞大而无法管理,此时最好使用语法分析程序生成器。
实际应用
- mysql中的sql语句解析。
- JDK中Pattern对正则表达式的编译和解析。
- Spring中ExpressionParser接口的使用。
更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)