解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。
给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
该模式对于复杂的场景实现起来比较困难,实际应用较少,大家了解即可。
模式结构Context(环境角色):声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret() 方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器 TerminalExpression 和非终结符解释器 NonterminalExpression 完成。
AbstractExpression(抽象解释器):实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面 R1 和 R2 就是终结符,对应的解析 R1 和 R2 的解释器就是终结符表达式。
TerminalExpression(终结符表达式):文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式 R=R1+R2 中,+ 就是非终结符,解析 + 的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
NoterminalExpression(非终结符表达式):这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如 R=R1+R2,我们给 R1 赋值 100,给 R2 赋值 200。这些信息需要存放到环境角色中,很多情况下我们使用 Map 来充当环境角色就足够了。
举例说明使用解释器模式实现数字的加减法
1、抽象解释器
/** * 抽象解释器 */ public abstract class AbstractExpression { public abstract int interpret(Context context); }2、非终结符表达式
/** * 非终结表达式:加法 */ public class AddExpression extends AbstractExpression { private final AbstractExpression left; private final AbstractExpression right; public AddExpression(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) + right.interpret(context); } } /** * 非终结表达式:减法 */ public class SubExpression extends AbstractExpression { private final AbstractExpression left; private final AbstractExpression right; public SubExpression(AbstractExpression left, AbstractExpression right) { this.left = left; this.right = right; } @Override public int interpret(Context context) { return left.interpret(context) - right.interpret(context); } }3、终结表达式
/** * 终结表达式:变量 */ public class Variable extends AbstractExpression { private final String key; public Variable(String key) { this.key = key; } @Override public int interpret(Context context) { return context.getValue(key); } }4、环境角色
/** * 环境上下文 */ public class Context { private final Map<String, Integer> valueMap = new HashMap<>(); public void addValue(final String key, final int value) { valueMap.put(key, value); } public int getValue(final String key) { return valueMap.get(key); } public Map<String, Integer> getValueMap() { return valueMap; } }5、测试类
public class Client { @Test public void test(){ Context context = new Context(); context.addValue("a", 6); context.addValue("b", 9); context.addValue("c", 1); Variable a = new Variable("a"); Variable b = new Variable("b"); Variable c = new Variable("c"); AbstractExpression addValue = new AddExpression(a, b); AbstractExpression subValue = new SubExpression(addValue, c); System.out.println(context.getValueMap()); System.out.println("a + b - c = " + subValue.interpret(context)); } }6、运行结果
{a=6, b=9, c=1} a+b-c=14 模式分析优点:
可扩展性比较好,灵活
增加了新的解释表达式的方式
易于实现简单文法
缺点:
可利用场景比较少
对于复杂的文法比较难维护
解释器模式会引起类膨胀
解释器模式采用递归调用方法
适用场景:
有一个简单的语法规则,比如一个 sql 语句,如果我们需要根据 sql 语句进行 rm 转换,就可以使用解释器模式来对语句进行解释。
一些重复发生的问题,比如加减乘除四则运算,但是公式每次都不同,有时是 a+b-cd,有时是 ab+c-d,等等等等个,公式千变万化,但是都是由加减乘除四个非终结符来连接的,这时我们就可以使用解释器模式。
参考23种设计模式(14):解释器模式
菜鸟教程 - 解释器模式
折腾Java设计模式之解释器模式