在软件构建过程中,若果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变
化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,再构建一个解释器来解释这样的句子,从而达到解决问题的目的。
给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 -GoF
Interpreter设计模式中的几种角色:
AbstractExpression:
- Declares an abstract Interpret operation that is common to all nodes in the abstract syntax tree.
TerminalExpression:
- Implements an Interpret operation associated with terminal symbols in the grammer.
- An instance is required for every terminal symbol in a sentence.
NonterminalExpression:
The other inherited class / implementation of the AbstractExpression abstract class / interface, intended ofr the nonterminal
nodes in the grammar and syntax tree. It keeps a reference to the next AbstractExpression(s) and invokes the interpret
method on each of its children.
- One such class is required for every rule R ::= R1R2…Rn in the grammer.
- Maintains instance variables of type AbstractExpression for each of the symbols R1 throught Rn.
- Implements an Interpret operation for nonterminal symbols in the grammar. Interpret typically calls itself recursively on the
variables representing R1 through Rn.
Context:
Container for the information that is needed in several places in the interpreter. It can serve as a communication channel among
serveral AbstractExpresssion instances.
- Contains information that’s global to the interpreter.
PatternClient:
Either builds or receives an instance of an abstract syntax tree. This syntax tree is composed of instances of
TerminalExpressions and NonterminalExpression to model a specific sentence. The PatternClient invokes the
interpret method with the appropriate context where necessary.
Interpreter模式的应用场合是interpreter模式应用中的难点,只有满足"业务规则频繁变化,且类似的模式不断重复出现,并且容易抽
象为语法规则的问题"才适合使用Interpreter模式。
使用Interpreter模式来表示文法规则,从而可以使用面向对象技巧来方便地“扩展”文法。
Interpreter模式比较适合简单的文法表示,对于复杂的文法表示,Interpreter模式会产生比较大的类层次结构,这时候就不应该采用
Interpreter模式了。
效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。例如:正则
表达式通常被转换成状态机。但即使在这种情况下,转换器仍可用解释器模式实现,该模式仍是有用的。
下面是一个将中文数字转换成阿拉伯数字的例子,其中用到了Interpreter:
// Context.java
package com.pnft.patterns.interpreter;
public class Context
{
private String statement;
private long data;
public Context(String statement)
{
this.statement = statement;
}
public String getStatement()
{
return statement;
}
public void setStatement(String statement)
{
this.statement = statement;
}
public long getData()
{
return data;
}
public void setData(long data)
{
this.data = data;
}
}
// Expression.java
package com.pnft.patterns.interpreter;
import java.util.Hashtable;
public abstract class Expression
{
protected Hashtable<String, Integer> dictionary = new Hashtable<String, Integer>();
public Expression()
{
dictionary.put("一", 1);
dictionary.put("二", 2);
dictionary.put("三", 3);
dictionary.put("四", 4);
dictionary.put("五", 5);
dictionary.put("六", 6);
dictionary.put("七", 7);
dictionary.put("八", 8);
dictionary.put("九", 9);
}
public void Interpret(Context ctx)
{
if(ctx.getStatement().length() == 0)
{
// 处理完成,返回
return;
}
else if(ctx.getStatement().endsWith("零"))
{
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - 1);
ctx.setStatement(tempstr);
return;
}
else
{
for(String key : dictionary.keySet())// 相当于C#中的foreach
{
int value = ((Integer)dictionary.get(key)).intValue();
if(ctx.getStatement().endsWith(key + GetPostfix()))
{
long tempdata = ctx.getData();
tempdata += value * Multiplier();
ctx.setData(tempdata);
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - this.GetLength());
ctx.setStatement(tempstr);
return;
}
}
}
}
public abstract String GetPostfix();
public abstract int Multiplier();
public int GetLength()
{
return this.GetPostfix().length() + 1;
}
}
// GeExpression.java
package com.pnft.patterns.interpreter;
public class GeExpression extends Expression
{
@Override
public String GetPostfix()
{
return "";
}
@Override
public int Multiplier()
{
return 1;
}
@Override
public int GetLength()
{
return 1;
}
}
// ShExpression.java
package com.pnft.patterns.interpreter;
public class ShExpression extends Expression
{
@Override
public String GetPostfix()
{
return "十";
}
@Override
public int Multiplier()
{
return 10;
}
}
// BaExpression.java
package com.pnft.patterns.interpreter;
public class BaExpression extends Expression
{
@Override
public String GetPostfix()
{
return "百";
}
@Override
public int Multiplier()
{
return 100;
}
}
// QiExpression.java
package com.pnft.patterns.interpreter;
public class QiExpression extends Expression
{
@Override
public String GetPostfix()
{
return "千";
}
@Override
public int Multiplier()
{
return 1000;
}
}
// WaExpression.java
package com.pnft.patterns.interpreter;
import java.util.ArrayList;
public class WaExpression extends Expression
{
@Override
public String GetPostfix()
{
return "万";
}
@Override
public int Multiplier()
{
return 10000;
}
@Override
public void Interpret(Context ctx)
{
if(ctx.getStatement().endsWith("零"))
{
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - 1);
ctx.setStatement(tempstr);
return;
}
if(ctx.getStatement().length() == 0)
{
// 处理完成,返回
return;
}
else
{
ArrayList<Expression> stxTree = new ArrayList<Expression>();
stxTree.add(new GeExpression());
stxTree.add(new ShExpression());
stxTree.add(new BaExpression());
stxTree.add(new QiExpression());
if(ctx.getStatement().endsWith(GetPostfix()))
{
long tempdata = ctx.getData();
ctx.setData(0);
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - 1);
ctx.setStatement(tempstr);
for(Expression exp : stxTree)
{
exp.Interpret(ctx);
}
ctx.setData(tempdata + ctx.getData() * this.Multiplier());
return;
}
}
}
}
// YiExpression.java
package com.pnft.patterns.interpreter;
import java.util.ArrayList;
public class YiExpression extends Expression
{
@Override
public String GetPostfix()
{
return "亿";
}
@Override
public int Multiplier()
{
return 100000000;
}
@Override
public void Interpret(Context ctx)
{
if(ctx.getStatement().endsWith("零"))
{
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - 1);
ctx.setStatement(tempstr);
return;
}
if(ctx.getStatement().length() == 0)
{
// 处理完成,返回
return;
}
else
{
ArrayList<Expression> stxTree = new ArrayList<Expression>();
stxTree.add(new GeExpression());
stxTree.add(new ShExpression());
stxTree.add(new BaExpression());
stxTree.add(new QiExpression());
stxTree.add(new WaExpression());
if(ctx.getStatement().endsWith(GetPostfix()))
{
long tempdata = ctx.getData();
ctx.setData(0);
String tempstr = ctx.getStatement();
tempstr = tempstr.substring(0, tempstr.length() - 1);
ctx.setStatement(tempstr);
for(Expression exp : stxTree)
{
exp.Interpret(ctx);
}
ctx.setData(tempdata + ctx.getData() * this.Multiplier());
return;
}
}
}
}
// PatternClient.java
package com.pnft.patterns.interpreter;
import java.util.ArrayList;
public class PatternClient
{
public static void main(String[] args)
{
String chineseNumber = "九万六千六百八十九亿零七百三十一万六千八百三十九";
Context ctx = new Context(chineseNumber);
// 构造语法树
ArrayList<Expression> syntaxTree = new ArrayList<Expression>();
syntaxTree.add(new GeExpression());
syntaxTree.add(new ShExpression());
syntaxTree.add(new BaExpression());
syntaxTree.add(new QiExpression());
syntaxTree.add(new WaExpression());
syntaxTree.add(new YiExpression());
// 开始解释
for(Expression exp : syntaxTree)
{
exp.Interpret(ctx);
}
System.out.println(chineseNumber + " = " + ctx.getData());
}
}
上述代码运行结果:
九万六千六百八十九亿零七百三十一万六千八百三十九 = 9668907316839
上述代码对应静态UML类图:
![](https://p-blog.csdn.net/images/p_blog_csdn_net/pathuang68/EntryImages/20090506/interpreter1.GIF)
上述程序的实际运算步骤:
"九万六千六百八十九亿零七百三十一万六千八百三十九" ctx.data = 0
"九万六千六百八十九亿零七百三十一万六千八百三十" ctx.data = 9
"九万六千六百八十九亿零七百三十一万六千八百" ctx.data = 39
"九万六千六百八十九亿零七百三十一万六千" ctx.data = 839
"九万六千六百八十九亿零七百三十一万" ctx.data = 6839 (将"万"去掉)
"九万六千六百八十九亿零七百三十一" ctx.data = 6839 ("零七百三十一"将递归地使用前面已有的Expression)
"九万六千六百八十九亿" ctx.data = 7316839 (将"亿"去掉)
"九万六千六百八十九" ctx.data = 7316839 ("九万六千六百八十九"将递归地使用前面已有的Expression)
ctx.data = 9668907316839