索引

意图

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

Given a language, define a represention for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

结构

参与者

AbstractExpression

  • 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。

TerminalExpression

  • 实现与文法中的终结符相关联的解释操作。
  • 一个句子中的每一个终结符需要该类的一个实例。

NonterminalExpression

  • 对文法中的规则的解释操作。

Context

  • 包含解释器之外的一些全局信息。

Client

  • 构建表示该语法定义的语言中一个特定的句子的抽象语法树。
  • 调用解释操作

适用性

当有个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可以使用 Interpreter 模式。

当存在以下情况时效果最好:

  • 该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。
  • 效率不是一个关键问题,最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。

效果

  • 易于改变和扩展文法。
  • 易于实现文法。
  • 复杂的文法难以维护。
  • 增加了新的解释表达式的方式。

相关模式

  • 抽象语法树是一个 Composite 模式的实例。
  • 可以使用 Flyweight 模式在抽象语法树中共享终结符。
  • 可以使用 Iterator 模式遍历解释器结构。
  • 可以使用 Visitor 模式在一个类中维护抽象语法树中的各个节点的行为。

实现

实现方式(一):Interpreter 模式结构样式代码。

TerminalExpression:实现解释 Terminal Symbols 的语法。

NonTerminalExpression:聚合一到多个 Expression,Expression 可以是 TerminalExpression,也可以是 NonTerminalExpression。。

 namespace InterpreterPattern.Implementation1
{
public class Context
{
public Context(string name)
{
Name = name;
} public string Name { get; private set; }
} public abstract class ExpressionBase
{
public abstract void Interpret(Context context);
} public class TerminalExpression : ExpressionBase
{
public override void Interpret(Context context)
{
Console.WriteLine("Terminal Symbol {0}.", context.Name);
}
} public class NonTerminalExpression : ExpressionBase
{
public ExpressionBase Expression1 { get; set; }
public ExpressionBase Expression2 { get; set; } public override void Interpret(Context context)
{
Console.WriteLine("Non Terminal Symbol {0}.", context.Name);
Expression1.Interpret(context);
Expression2.Interpret(context);
}
} public class Client
{
public void TestCase1()
{
var context = new Context("Hello World");
var root = new NonTerminalExpression
{
Expression1 = new TerminalExpression(),
Expression2 = new TerminalExpression()
};
root.Interpret(context);
}
}
}

实现方式(二):解释波兰表达式(Polish Notation)。

中缀表达式

中缀表达式中,二元运算符总是置于与之相关的两个运算对象之间,根据运算符间的优先关系来确定运算的次序,同时考虑括号规则。
比如: 2 + 3 * (5 - 1)

前缀表达式

波兰逻辑学家 J.Lukasiewicz 于 1929 年提出了一种不需要括号的表示法,将运算符写在运算对象之前,也就是前缀表达式,即波兰式(Polish Notation, PN)。
比如:2 + 3 * (5 - 1) 这个表达式的前缀表达式为 + 2 * 3 - 5 1

后缀表达式

后缀表达式也称为逆波兰式(Reverse Polish Notation, RPN),和前缀表达式相反,是将运算符号放置于运算对象之后。
比如:2 + 3 * (5 - 1) 用逆波兰式来表示则是:2 3 5 1 - * +

 namespace InterpreterPattern.Implementation2
{
public interface IExpression
{
int Evaluate();
} public class IntegerTerminalExpression : IExpression
{
int _value; public IntegerTerminalExpression(int value)
{
_value = value;
} public int Evaluate()
{
return _value;
} public override string ToString()
{
return _value.ToString();
}
} public class AdditionNonterminalExpression : IExpression
{
private IExpression _expr1;
private IExpression _expr2; public AdditionNonterminalExpression(
IExpression expr1,
IExpression expr2)
{
_expr1 = expr1;
_expr2 = expr2;
} public int Evaluate()
{
int value1 = _expr1.Evaluate();
int value2 = _expr2.Evaluate();
return value1 + value2;
} public override string ToString()
{
return string.Format("({0} + {1})", _expr1, _expr2);
}
} public class SubtractionNonterminalExpression : IExpression
{
private IExpression _expr1;
private IExpression _expr2; public SubtractionNonterminalExpression(
IExpression expr1,
IExpression expr2)
{
_expr1 = expr1;
_expr2 = expr2;
} public int Evaluate()
{
int value1 = _expr1.Evaluate();
int value2 = _expr2.Evaluate();
return value1 - value2;
} public override string ToString()
{
return string.Format("({0} - {1})", _expr1, _expr2);
}
} public interface IParser
{
IExpression Parse(string polish);
} public class Parser : IParser
{
public IExpression Parse(string polish)
{
var symbols = new List<string>(polish.Split(' '));
return ParseNextExpression(symbols);
} private IExpression ParseNextExpression(List<string> symbols)
{
int value;
if (int.TryParse(symbols[], out value))
{
symbols.RemoveAt();
return new IntegerTerminalExpression(value);
}
return ParseNonTerminalExpression(symbols);
} private IExpression ParseNonTerminalExpression(List<string> symbols)
{
var symbol = symbols[];
symbols.RemoveAt(); var expr1 = ParseNextExpression(symbols);
var expr2 = ParseNextExpression(symbols); switch (symbol)
{
case "+":
return new AdditionNonterminalExpression(expr1, expr2);
case "-":
return new SubtractionNonterminalExpression(expr1, expr2);
default:
{
string message = string.Format("Invalid Symbol ({0})", symbol);
throw new InvalidOperationException(message);
}
}
}
} public class Client
{
public void TestCase2()
{
IParser parser = new Parser(); var commands =
new string[]
{
"+ 1 2",
"- 3 4",
"+ - 5 6 7",
"+ 8 - 9 1",
"+ - + - - 2 3 4 + - -5 6 + -7 8 9 0"
}; foreach (var command in commands)
{
IExpression expression = parser.Parse(command);
Console.WriteLine("{0} = {1}", expression, expression.Evaluate());
} // Results:
// (1 + 2) = 3
// (3 - 4) = -1
// ((5 - 6) + 7) = 6
// (8 + (9 - 1)) = 16
// (((((2 - 3) - 4) + ((-5 - 6) + (-7 + 8))) - 9) + 0) = -24
}
}
}

设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。

设计模式之美:Interpreter(解释器)的更多相关文章

  1. 设计模式15:Interpreter 解释器模式(行为型模式)

    Interpreter 解释器模式(行为型模式) 动机(Motivation) 在软件构建过程中,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变 ...

  2. Java设计模式(17)解释器模式(Interpreter模式)

    Interpreter定义:定义语言的文法,并且建立一个解释器来解释该语言中的句子. Interpreter似乎使用面不是很广,它描述了一个语言解释器是如何构成的,在实际应用中,我们可能很少去构造一个 ...

  3. 设计模式之美:Visitor(访问者)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Visitor 模式结构样式代码. 实现方式(二):使用 Visitor 模式解构设计. 实现方式(三):使用 Acyclic ...

  4. 《设计模式之美》 <03>面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?

    面向对象 现在,主流的编程范式或者是编程风格有三种,它们分别是面向过程.面向对象和函数式编程.面向对象这种编程风格又是这其中最主流的.现在比较流行的编程语言大部分都是面向对象编程语言.大部分项目也都是 ...

  5. 23、Interpreter 解释器模式

    1.Interpreter 解释器模式 解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器.在某些情况下,为了更好地描述某一些特定类型的问 ...

  6. 设计模式之美:Product Trader(操盘手)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Product Trader 的示例实现. 意图 使客户程序可以通过命名抽象超类和给定规约来创建对象. Product Trad ...

  7. 设计模式之美:Null Object(空对象)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Null Object 的示例实现. 意图 通过对缺失对象的封装,以提供默认无任何行为的对象替代品. Encapsulate t ...

  8. 设计模式之美:Dynamic Property(动态属性)

    索引 别名 意图 结构 参与者 适用性 效果 实现 实现方式(一):Dynamic Property 的示例实现. 别名 Property Properties Property List 意图 使对 ...

  9. 设计模式之美:Role Object(角色对象)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Role Object 的示例实现. 意图 通过明确地附加角色对象到目标对象中,以使对象可以适配不同的客户需求.每个角色对象都代 ...

随机推荐

  1. 123. Best Time to Buy and Sell Stock (三) leetcode解题笔记

    123. Best Time to Buy and Sell Stock III Say you have an array for which the ith element is the pric ...

  2. 【java】:枚举小demo

    package com.jwis.study.enumeration; /** * @author lx * 枚举的一些方法 */ //⑴ enum Substar{tst1,tst2,ts3} pu ...

  3. 父窗口,子窗口之间的JS"通信"方法

    今天需要在iframe内做一个弹窗,但使用弹窗组件的为子窗口,所以弹窗只在子窗口中显示掩膜层和定位,这样不符合需求. 后来晓勇哥指点,了解到一个以前一直没关注到的东西,每个窗口的全局变量,其实都存在对 ...

  4. Dancing Links & Algorithm X

    1 参考链接 http://www.cnblogs.com/steady/archive/2011/03/15/1984791.html#undefined http://en.wikipedia.o ...

  5. 最小生成树算法——Kruskal算法

    #include<stdio.h> #include<algorithm> #include<windows.h> using namespace std; str ...

  6. ApiDoc 文档使用方式

    1.安装node.js 2.打开node.js 命令窗(shell)键入npm install apidoc -g 自动安装(几分钟) 3. C:\Users\user\AppData\Roaming ...

  7. python3下安装Django

    1.下载python3 https://www.Python.org/ 我下载的是Python3.5.1 选的 Windows x86-64 executable installer 2. 打开cmd ...

  8. Log4j的ConversionPattern无缝适配到Logback

    为了能将log4j的ConversionPattern无缝应用到logback上来,需要对两个Conversion做适配,具体可以参考:Log4j 与 Logback的ConversionPatter ...

  9. Integrate non-OSGi Dependencies

    Consider a scenario where you need to use a non-OSGi jar in your OSGi project. Most libraries are no ...

  10. css中关于position属性的探究(原创)

    关于position属性的设置,头脑中一直觉得不是很清楚,所以借助这次机会单独自己测试了一下,记作学习笔记.   首先,css的position属性包含下面四种设置情况: static:默认属性.指定 ...