Interpeter解释模式:给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。 ——《设计模式》
在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。
Interpeter解释模式:给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。 ——《设计模式》
在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。此模式在实际应用中并不常见。
Interpeter解释模式有以下角色:
如图:
1、Client客户程序:它是Interpreter模式的使用者,我们通常在此对Context进行初步分析,并形成一个表达式树(通常这个树保存在ArrayList中),这个树中的每一个节点表示要进行的操作(Terminal或NonTermianl类型的操作),这项工作通常打包在一个类中,在本例我们把它放在名为Parse的类中进行。
2、Context上下文:它就是我们要进行翻译解释的语句,是我们进行操作原材料。
3、Expression抽象类:它是一个接口,TerminalExpression类与NonterminalExpression类均继承自此类,它定义了Interpret方法,并要求在其子类中实现此方法。
4、TerminalExpression类: 它继承自Expression抽象类,它针对语句“分解”的功能成分比较少,主要是针对"最终原子"对象的处理。比如本例,对数学计算式分解后得到的整数的处理。
5、NonterminalExpression类:它继承自Expression抽象类,它针对不同的语法情况需要定义不同的处理方式,所以通常我们需要在此处进行扩展,例如本例我们定义了针对"+"与"-"法的语法处理,如果需要用到"*"与"/",则我们也需要在此另外扩展相应的NonterminalExpression类。
这里,我们就以一个数学计算式为例来进行说明:我们需要做的工作就是把左边的表达式翻译成右边的形式并加以计算,情况如下:
"+ 7 8" 处理后 (7+8)=15
"- 8 2" 处理后 (8-2)=6
"+ - 3 8 6" 处理后 ((3-8)+6)=1
"+ 2 - 7 6" 处理后 (2+(7-6))=3
一、Interpreter模式流程示例
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Interpreter
{
//被Interpreter解释的上下文内容Context
//比如把中文的"五千四百三十二"解释为5432,则"五千四百三十二"就是Context
public class Context
{
public string Name { get; set; }
public Context(string name)
{
Name = name;
}
}
//声明一个接口,定义执行Interpert操作,操作对象就是Context,也即对它进行语法解释
//TerminalExpression与NonterminalExpression将继承自此接口
public abstract class Expression
{
public abstract void Interpret(Context context);
}
//针对上面Context中的"千,百,十"等各种最小的语句结构进行最终的分析
//也即,对"五千","四百","三十","二"这样的最小语句结构进行最终分析
//例如:"五千四百万"与"五千","四百",它们其实是不同的数字
//"五千四百万"中的五千与四百应属于"万位"数
//而后面的"五千","四百"而分别属于"千位"与"百位数"
//虽然它们属于不的"位数",但针对它们的解释方法是一样的,所以可以放到TerminalExpression中操作
//但操作后的结果应放在什么"位数"上,则由各自对应的NonterminalExpression来决定,即由Expression1,Expression2.ExpressionN来对应
public class TerminalExpression : Expression
{
public override void Interpret(Context context)
{
Console.WriteLine("Terminal for {0}.", context.Name);
}
}
//针对每一种语法情况都需要在此定义一个解释器,例如:"二百三十万" "四千" "三十","五",则针对万,千,十位,个位它们的语法表达规律是不一样的
//所以需要针对"万位数","千位数","百位数","十位数","个位数"每一种情况的语法规律定制有所针对性的解释器
public class NonterminalExpression : Expression
{
public Expression Expression1 { get; set; } //可理解为针对"万位数"的解释
public Expression Expression2 { get; set; } //可理解为针对"千位数"的解释
public override void Interpret(Context context)
{
Console.WriteLine("Nonterminal for {0}.", context.Name);
Expression1.Interpret(context);
Expression2.Interpret(context);
}
}
}
在Client中展示流程
#region 演示流程
Console.WriteLine("-------Interpreter模式处理流程-------");
Context context = new Context("the context");
NonterminalExpression root = new NonterminalExpression();
root.Expression1 = new TerminalExpression();
root.Expression2 = new TerminalExpression();
root.Interpret(context);
Console.ReadKey();
#endregion
二、数学计算式的Interpreter模式应用
1、Context角色:此角色在实际应用中可有可没有,我们在这里并不需要它,但此处为完整,还是给出一个定义
public class Context
{
public string Name { get; set; }
public Context(string name)
{
Name = name;
}
}
2、Expression抽象类角色
#region 定义一个Expression接口
public abstract class ExpressionBase
{
public abstract int Evaluate();
}
#endregion
3、TerminalExpression类角色
Code
#region 定义TerminalExpression
#region 定义IntegerExpression类,它是TerrminalExpression
public class IntegerExpression : ExpressionBase
{
int _value;
public IntegerExpression(int value)
{
_value = value;
}
public override int Evaluate()
{
return _value;
}
public override string ToString()
{
return _value.ToString();
}
}
#endregion
#endregion
4、NonterminalExpression类角色
Code
#region 定义NonterminalExpression
//当然,我们还可以加入针对"*"号与"/"号的NonterminalExpression
#region AdditionExpression 针对"+"号的NonterminalExpression
public class AdditionExpression : ExpressionBase
{
ExpressionBase _expr1;
ExpressionBase _expr2;
public AdditionExpression(ExpressionBase expr1, ExpressionBase expr2)
{
_expr1 = expr1;
_expr2 = expr2;
}
public override int Evaluate()
{
int value1 = _expr1.Evaluate();
int value2 = _expr2.Evaluate();
return value1 + value2;
}
public override string ToString()
{
return string.Format("({0} + {1})", _expr1, _expr2);
}
}
#endregion
#region SubtractionExpression 针对"-"号的NonterminalExpression
public class SubtractionExpression : ExpressionBase
{
ExpressionBase _expr1;
ExpressionBase _expr2;
public SubtractionExpression(ExpressionBase expr1, ExpressionBase expr2)
{
_expr1 = expr1;
_expr2 = expr2;
}
public override int Evaluate()
{
int value1 = _expr1.Evaluate();
int value2 = _expr2.Evaluate();
return value1 - value2;
}
public override string ToString()
{
return string.Format("({0} - {1})", _expr1, _expr2);
}
}
#endregion
#endregion
5、定义Parser,它负责对Context进行分解
Code
#region 定义Parser,它负责对Context进行分解
//并负责组织TerminalExpression与NontermianlExpression方法对Context进行处理
public class Parser
{
public ExpressionBase Parse(string polish)
{
List<string> symbols = new List<string>(polish.Split(' '));
return ParseNextExpression(symbols);
}
public ExpressionBase ParseNextExpression(List<string> symbols)
{
int value;
if (int.TryParse(symbols[0], out value))
{
symbols.RemoveAt(0);
return new IntegerExpression(value);
}
else
{
return ParseNonTerminalExpression(symbols);
}
}
private ExpressionBase ParseNonTerminalExpression(List<string> symbols)
{
string symbol = symbols[0];
symbols.RemoveAt(0);
ExpressionBase expr1 = ParseNextExpression(symbols);
ExpressionBase expr2 = ParseNextExpression(symbols);
switch (symbol)
{
case "+":
return new AdditionExpression(expr1, expr2);
case "-":
return new SubtractionExpression(expr1, expr2);
default:
string message = string.Format("Invalid Symbol ({0})", symbol);
throw new InvalidOperationException(message);
}
}
}
#endregion
6、Client客户程序角色
Code
#region 演示数学计算式的语法解释
Console.WriteLine("-------数学计算工Interpreter模式应用-------");
Parser parser = new Parser();
string[] commands = new string[]
{
"+ 7 8",
"- 8 2",
"+ - 3 8 6",
"+ 2 - 7 6",
"+ - + - - 2 3 4 + - -5 6 + -7 8 9 10"
};
foreach (string command in commands)
{
ExpressionBase expression = parser.Parse(command);
Console.WriteLine("{0} = {1}", expression, expression.Evaluate());
}
Console.ReadKey();
#endregion
程序如下图:
运行效果如下图:
总结:
Interpreter 模式的几个要点
1、Interpreter模式的应用场合是中的难点,只有满足Interpreter模式应用“业务规则频繁变化,且类似的模式不断重复出现,并且容易抽象为语法规则的问题”才适合使用Interpreter模式。
2、使用Interpreter 模式来表示文法规则,从而可以使用面向对象技巧来方便地“扩展”文法。
3、Interpreter 模式比较适合简单的文法表示,对于复杂的文法表示,Interperter 模式会产生比较大的类层次结构,需要求助于语法分析生成器这样的标准工具。
前往:设计模式学习笔记清单