目录
解释器模式
引言
解释器模式主要使用于面向对象语言开发的编译器和解释器设计,平时不常使用。在某些情况下,为了更好地描述某一些特定的问题,可以创建一个新的语言,这个语言拥有自己的表达式和结构,即语法规则,而且可以根据需要灵活的增加新的语法规则。
定义
英文定义:“Given a language,define a representation for its grammar along with an interpreter that use the representation to interpret sentences in the language.”。
中文定义:定义语言的文法,并且建立一个解释器来解释该语言中的句子。
解释器模式重要等级★☆☆☆☆ 解释器模式难度等级★★★★☆
模式结构图
解释器模式包含如下角色。
1)AbstractExpression(抽象表达式)
2)TerminalExpression(终结符表达式)
终结符表达式是抽象表达式的子类,它实现了文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较复杂的句子。
3)NonTerminalExpression(非终结符表达式)
非终结符表达式是抽象表达式的子类,它实现了文法中非终结符的解释操作。由于非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归方式来完成。
4)Interpreter(解释器封装类)
该类中构造了表示该文法的语言中一个特定句子的抽象语法树,该抽象语法树由非终结符表达式和终结表达式实例组合而言。改类中调用解释操作,实现对句子的解释。
实例
实例说明
使用解释器模式设计一个简单的加法/减法解释器。
实例类图
代码实现
1)抽象节点类Node
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
interface Node
{
int Interpret();
}
2) 终结符表达式ValueNode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class ValueNode : Node
{
private int value;
public ValueNode(int value)
{
this.value = value;
}
public int Interpret()
{
return value;
}
}
3) 非终结符表达式SymbolNode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
abstract class SymbolNode:Node
{
protected Node left;
protected Node right;
public SymbolNode(Node left,Node right)
{
this.left = left;
this.right = right;
}
public abstract int Interpret();
}
4)AddNode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class AddNode : SymbolNode
{
public AddNode(Node left, Node right) : base(left, right) { }
public override int Interpret()
{
return left.Interpret() + right.Interpret();
}
}
5) SubtractNode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class SubtractNode : SymbolNode
{
public SubtractNode(Node left,Node right) : base(left, right) { }
public override int Interpret()
{
return left.Interpret() - right.Interpret();
}
}
6) Calculator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Calculator
{
private Node node;
public int Compute(string statement)
{
BuildTree(statement);
return node.Interpret();
}
private void BuildTree(string statement)
{
Node left, right;
Stack<Node> nodes = new Stack<Node>();
string[] arr = statement.Split(' ');
for(int i = 0; i < arr.Length; i++)
{
string v = arr[i];
if (v.Equals("+"))
{
left = nodes.Pop();
right = new ValueNode(Convert.ToInt16(arr[++i]));
nodes.Push(new AddNode(left, right));
}
else if (v.Equals("-"))
{
left = nodes.Pop();
right = new ValueNode(Convert.ToInt16(arr[++i]));
nodes.Push(new SubtractNode(left, right));
}
else
{
nodes.Push(new ValueNode(Convert.ToInt16(v)));
}
}
node = nodes.Pop();
}
}
测试代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Calculator caculator = new Calculator();
string formula = Console.ReadLine();
Console.WriteLine(formula + " = " + caculator.Compute(formula));
Console.ReadKey();
}
}
运行截图
总结
模式优点
1)易于改变和扩展文法。由于解释器模式使用类来表示语言的文法规则,因此可以通过继承机制来改变或者扩展文法。
2)易于实现文法。在抽象语法树中每一个节点类的实现方式都是相似的,这些类的编写都不是很复杂。
3)增加了新的解释表达式的方式。解释器模式可以让用户较为方便地增加新类型的表达式,增加新的表达式时无需对现有表达式进行修改,符合“开闭原则”。
模式缺点
1)对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,则可能难以管理和维护。
2) 执行效率低。因为解释器模式中使用了大量的递归和循环调用。
3)应用场景有限,在实际开发中很少需要自定义文法规则。