十八.行为型设计模式——Interpreter Pattern(解释器模式)
-
定义
给出一种语言,定义这种语言的文法的一种表示,定义一个解释器,用它来解释使用这种语言的句子。
UML类图如下:
其中类和对象之间的关系为:
1.AbstractExpression(抽象表达式类):定义一个接口来执行解释操作。
2.TerminalExpression(终结符表达式):实现文法中管理终结符的解释操作;文句中的每个终结符都需要一个实例。
3.NonterminalExpression(非终结符表达式):文法中的每一条规则R::=R1R2....Rn都需要一个非终结符表达式类;维护每一条规则R1到Rn具有AbstractExpression接口实例;实现文法中关联非终结符的解释操作,采用递归的办法调用每一条规则R1到Rn的解释操作。
4.Context(场景):包含解释器的所有全局信息。
5.Client(客户应用程序):建造(或被给定)由这种语言表示的句子的抽象文法树,文法树由终结符表达式或者非终结符表达式的实例组成;调用文法树中的表达式实例的解释操作。
典型应用的顺序图如下:
客户先讲内容(context,又称上下文)分解生成多个非终结符号,再递归解释,直到所有终结符得到解释。
-
实例1——中国金钱大写转换
Interpreter模式的经典应用就是描述相同事情的不同语言转换。将中文的大写金额转换成阿拉伯数字表示就是一个例子。本例中没有用到nonTerminalExpression(非终结符)的类。
class Context
{
private string input;
private int output;
public Context(string input)
{
this.input = input;
}
public string Input
{
get { return input; }
set { input = value; }
}
public int Output
{
get { return output; }
set { output = value; }
}
}
//抽象表达式类
abstract class Expression
{
public abstract string One();
public abstract string Four();
public abstract string Five();
public abstract string Nine();
public abstract int Multiplier();
public void Interpret(Context context)
{
if (context.Input.Length == 0)
return;
if (context.Input.StartsWith(Nine()))
{
context.Output += 9 * Multiplier();
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Nine()))
{
context.Output += 9 * Multiplier();
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Four()))
{
context.Output += 4 * Multiplier();
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(Five()))
{
context.Output += 5 * Multiplier();
context.Input = context.Input.Substring(2);
}
else if (context.Input.StartsWith(One()))
{
context.Output += 1 * Multiplier();
context.Input = context.Input.Substring(2);
}
}
}
//核对千位上的文字
class ThousandExpression : Expression
{
public override string One() { return "壹仟"; }
public override string Four() { return "肆仟"; }
public override string Five() { return "伍仟"; }
public override string Nine() { return "玖仟"; }
public override int Multiplier() { return 1000; }
}
//核对百位上的文字
class HundredExpression : Expression
{
public override string One() { return "壹百"; }
public override string Four() { return "肆百"; }
public override string Five() { return "伍百"; }
public override string Nine() { return "玖百"; }
public override int Multiplier() { return 100; }
}
//核对十位上的文字
class TenExpression : Expression
{
public override string One() { return "壹拾"; }
public override string Four() { return "肆拾"; }
public override string Five() { return "伍拾"; }
public override string Nine() { return "玖拾"; }
public override int Multiplier() { return 10; }
}
//核对个位上的文字
class OneExpression : Expression
{
public override string One() { return "壹圆"; }
public override string Four() { return "肆圆"; }
public override string Five() { return "伍圆"; }
public override string Nine() { return "玖圆"; }
public override int Multiplier() { return 1; }
}
class Program
{
static void Main(string[] args)
{
string chinese = "壹仟伍百玖拾伍圆";
Context context = new Context(chinese);
ArrayList parse = new ArrayList();
parse.Add(new ThousandExpression());
parse.Add(new HundredExpression());
parse.Add(new TenExpression());
parse.Add(new OneExpression());
foreach (Expression exp in parse)
{
exp.Interpret(context);
}
Console.Write("{0} = {1}", chinese, context.Output);
Console.Read();
}
}
-
优势和缺陷:
解释器模式的作用很强大,它使得改变和扩展文法变得容易,实现文法也变得简单明了,很多编译器,包括文本编辑器、网页浏览器及VRML都应用解释器模式。
解释器模式的缺陷就是,因为文句会分析成树结构,解释器需要递归访问它,所以效率会受影响。这种情况开发人员会有所体会,编译整个工程源码耗费时间都比较长。
-
应用情景:
下面的情景很适合应用解释器模式:
1.语言的文法需要扩展。
2.程序效率不太重要。