设计模式学习笔记-解释器模式
概述:
解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
适用场合:
当一个语言需要解释执行,并且你可以将该语句中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好。
1.该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。
2.效率不是一个关键问题,最高效的解释器通常不是通过直接解析语法分析树实现的,而是首先将他们转换成另一种形式。
类图:
代码示例:
1.抽象表达式类
/// <summary>
/// 声明一个抽象的解释操作,这个接口为抽象语树中所有节点共享
/// </summary>
abstract class AbstractExpression
{
public abstract void Interpret(Context context);
}
2.全局信息类
/// <summary>
/// 包含解释器之外的一些全局信息
/// </summary>
class Context
{
private string input;
public string Input
{
get { return input; }
set { input = value; }
}
private string output;
public string Output
{
get { return output; }
set { output = value; }
}
}
3.终结符表达式类
/// <summary>
/// 终结符表达式,实现与文法中的终结符相关联的解释操作。
/// 实现抽象表达式中所要求的接口,主要是一个interpret方法,
/// 文中每一个终结符都有一个具体中介表达式与之相对应。
/// </summary>
class TerminalExpression:AbstractExpression
{
public override void Interpret(DesignPatternLab.InterpreterPackage.Context context)
{
Console.WriteLine("终端解释器");
}
}
4.非终结符表达式类
/// <summary>
/// 非终结符表达式,为文法的非终结符实现解释操作。对文法中每一条规则
/// 都需要一个具体的非终结符表达式类。通过实现抽象表达式的interpret
/// 方法实现解释操作,解释操作以递归的方式调用实例变量
/// </summary>
class NonterminalExpression:AbstractExpression
{
public override void Interpret(Context context)
{
Console.WriteLine("非终端解释器");
}
}
5.客户端调用
/// <summary>
/// 测试解释器模式
/// </summary>
static void TestInterpret()
{
DesignPatternLab.InterpreterPackage.Context context = new InterpreterPackage.Context();
IList<AbstractExpression> list = new List<AbstractExpression>();
list.Add(new TerminalExpression());
list.Add(new NonterminalExpression());
list.Add(new NonterminalExpression());
list.Add(new TerminalExpression());
foreach(AbstractExpression exp in list)
{
exp.Interpret(context);
}
Console.Read();
}
小结:
解释器模式一般应用在正则表达式应用,浏览器程序上,下面列举一个汉字数字大小写转换的例子加深理解
汉字数字大小写转换
/// <summary>
/// 抽象表达式角色
/// </summary>
public abstract class Expression
{
/// <summary>
/// 汉字数字与阿拉伯数字数字的对应字典
/// </summary>
protected Dictionary<string, int> table = new Dictionary<string, int>(9);
public Expression()
{
table.Add("壹", 1);
table.Add("贰", 2);
table.Add("参", 3);
table.Add("肆", 4);
table.Add("伍", 5);
table.Add("陆", 6);
table.Add("柒", 7);
table.Add("捌", 8);
table.Add("玖", 9);
}
/// <summary>
/// 所有的具体表达式角色都需要实现的抽象方法
/// 这个方法为虚方法,并非抽象方法,为了代码复用
/// </summary>
/// <param name="context">环境角色</param>
public virtual void Interpret(ContextcnNum context)
{
//如果要处理的字符串长度为0则返回
if (context.statement.Length == 0)
{
return;
}
foreach (string key in table.Keys)
{
int value = table[key];
if (context.statement.EndsWith(key + GetPostifix()))
{
context.data += value * Multiplier();
context.statement = context.statement.Substring(0, context.statement.Length - this.GetLength());
break;
}
if (context.statement.EndsWith("零"))
{
context.statement = context.statement.Substring(0, context.statement.Length - 1);
break;
}
if (context.statement.Length == 0)
{
return;
}
}
}
/// <summary>
/// 取汉字数字单位
/// 个位数为空
/// 十位数为十
/// 百位数为百
/// 千位数为千
/// </summary>
/// <returns></returns>
public abstract string GetPostifix();
/// <summary>
/// 例如:个位上数字为2,则最后为2*1
/// 例如:百位上数字为3,则表示3*10
/// </summary>
/// <returns></returns>
public abstract int Multiplier();
/// <summary>
/// 例如:个位的长度为一位
/// 例如数字三十,表示两位
/// 例如四百,表示两位
/// </summary>
/// <returns></returns>
public virtual int GetLength()
{
return this.GetPostifix().Length + 1;
}
}
/// <summary>
/// 终结符表达式角色
/// 如果能换算成数字则直接换算后返回
/// </summary>
class NumTerminalExpression : Expression
{
/// <summary>
/// 重写解释方法
/// </summary>
/// <param name="context">环境角色</param>
public override void Interpret(ContextcnNum context)
{
int i = 0;
try
{
i = int.Parse(context.statement);
//如果是数字则说明能够直接转换
//也就是说用不到非终结表达式角色
context.statement = "";
context.data = i;
}
catch
{
//说明输入的是汉字数字,不做任何处理
}
}
public override string GetPostifix()
{
return "";
}
public override int Multiplier() { return 1; }
}
/// <summary>
/// 非终结表达式角色
/// 解释个位数
/// </summary>
public class NonterminalOneExpression : Expression
{
public override string GetPostifix()
{
return "";
}
public override int Multiplier() { return 1; }
public override int GetLength()
{
return 1;
}
}
/// <summary>
/// 非终结表达式角色
/// 解释十位数
/// </summary>
public class NonterminalTenExpression : Expression
{
public override string GetPostifix()
{
return "拾";
}
public override int Multiplier() { return 10; }
public override int GetLength()
{
return 2;
}
}
/// <summary>
/// 非终结表达式角色
/// 解释百位数
/// </summary>
public class NonterminalHundredExpression : Expression
{
public override string GetPostifix()
{
return "百";
}
public override int Multiplier() { return 100; }
public override int GetLength()
{
return 2;
}
}
/// <summary>
/// 非终结表达式角色
/// 解释千位数
/// </summary>
public class NonterminalThousandExpression : Expression
{
public override string GetPostifix()
{
return "千";
}
public override int Multiplier() { return 1000; }
public override int GetLength()
{
return 2;
}
}
/// 环境角色
/// </summary>
public class ContextcnNum
{
/// <summary>
/// 汉字表示的数字
/// </summary>
public string statement
{
get;
set;
}
/// <summary>
/// 阿拉伯数字
/// </summary>
public int data
{
get;
set;
}
/// <summary>
/// 构造函数
/// 接受一个汉字表达式数字
/// </summary>
/// <param name="statement">汉字表达式数字</param>
public ContextcnNum(string statement)
{
this.statement = statement;
}
}
/// <summary>
/// 测试解释器模式例子
/// </summary>
static void TestInterpretSample()
{
string roman = "伍千肆百参拾贰"; //5432
ContextcnNum context = new ContextcnNum(roman);
//构造抽象语法树
ArrayList tree = new ArrayList();
//加入终结符表达式
//如果能直接转换成数字则直接返回
tree.Add(new NumTerminalExpression());
//非终结符,处理个位数
tree.Add(new NonterminalOneExpression());
//非终结符,处理十位数
tree.Add(new NonterminalTenExpression());
//非终结符,处理百位数
tree.Add(new NonterminalHundredExpression());
//非终结器,处理千位数
tree.Add(new NonterminalThousandExpression());
//对抽象语法树的每个枝节进行解释操作
foreach (Expression exp in tree)
{
exp.Interpret(context);
}
Console.WriteLine("{0} = {1}", roman, context.data);
Console.Read();
}