解释器模式顾名思义,就是给定句子和文法,然后进行解释的一种设计模式。是一种应用很少的模式,涉及到文法、语义等东西,没有基础很不好理解,更容易把设计的模式变得一坨一坨的,不容易维护更不容易理解。
解释器模式涉及到四个角色:
抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称做解释操作。
终结符表达式(Terminal Expression)角色:实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
非终结符表达式(Nonterminal Expression)角色:文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式。
环境(Context)角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。
意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
主要解决:对于一些固定文法构建一个解释句子的解释器。
何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
如何解决:构件语法树,定义终结符与非终结符。
关键代码:构件环境类,包含解释器之外的一些全局信息,一般是 HashMap。
应用实例:编译器、运算表达式计算。
优点:1、可扩展性比较好,灵活。2、增加了新的解释表达式的方式。3、易于实现简单文法。
缺点:1、可利用场景比较少。2、对于复杂的文法比较难维护。3、解释器模式会引起类膨胀。4、解释器模式采用递归调用方法。
使用场景:1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。2、一些重复出现的问题可以用一种简单的语言来进行表达。3、一个简单语法需要解释的场景。
注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。
由于这个模式很不容易理解,所以写了一个很简单的例子,自增和自减的方法:
<?php
//上下文类
class Context{
public $Num;
function Set($Num)
{
$this->Num = $Num;
}
function Get()
{
return $this->Num;
}
}
//抽象解释器
abstract class AbstractExpreesion{
abstract function Interpret(Context $Context);
}
//自加解释器
class PlusExpression extends AbstractExpreesion{
function Interpret(Context $Context)
{
$Context->Num = $Context->Num+1;
}
}
//自减解释器
class MinusExpression extends AbstractExpreesion{
function Interpret(Context $Context)
{
$Context->Num = $Context->Num-1;
}
}
//调用
//上下文
$Context = new Context();
$Context->Set(100);
//加减法
$PlusExpression = new PlusExpression();
$MinusExpression = new MinusExpression();
//两次自加一次自减
$PlusExpression->Interpret($Context);
$PlusExpression->Interpret($Context);
$MinusExpression->Interpret($Context);
//输出
echo $Context->Get();
?>