索引

意图

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

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. 使用cookie实现计数器功能

    思路是:若第一次访问,创建cookie.若访问次数大于一,则先读出cookie值赋给一个值,然后再重新写入cookie. <?php if(!isset($_COOKIE['num'])){ $ ...

  2. 搭建高可用mongodb集群(三)—— 深入副本集内部机制

    在上一篇文章<搭建高可用mongodb集群(二)—— 副本集> 介绍了副本集的配置,这篇文章深入研究一下副本集的内部机制.还是带着副本集的问题来看吧! 副本集故障转移,主节点是如何选举的? ...

  3. matplotlib 随记

    1.安装 window平台下推荐安装Enthought canopy,包含matplotlib和它所依赖的包: linux下一般默认内置了matplotlib,直接使用就可以了.   2.在没有图形界 ...

  4. Ext JS

    官網:http://www.sencha.com/products/extjs/

  5. struts2中如何使用主题theme

    一.什么是主题? 主题就是一种风格化标签,能够让所有UI标签能够产生同样的视觉效果而归集到一起的一组模板,即风格相近的模板被打包为一个主题 二.struts2提供的主题有哪些呢?struts2中如何修 ...

  6. Html/Css(新手入门第三篇)

    一.学习心得---参考优秀的网页来学习. 1我们只做的静态网页主要用的技术?html+css 只要网上看到的,他的源代码公开的.[1].先去分析,他们页面是如何布局(结构化)[2].再试着去做一下,- ...

  7. liunx 多个tomcat 产生的新问题

    今天在给 tomcat 版本7.0.57升级到7.0.72的时候,碰到一个奇怪的问题,启动 tomcat7.0.72 的时候报错,找不到tomcat7.0.57/bin/setclasspath.sh ...

  8. maven 环境的配置 JAVA_HOME not found in your envirnment

    maven 的环境配置在配置maven前 先做好java的环境配置现在假定java已经配置好了.在环境变量中添加;maven的解压路径\bin 例如:D:\soft\java\apache-maven ...

  9. Redis多机常用架构-cluster

    Redis-cluster:去中心化,中间件,集群中任意节点平等,任一节点可获得全局的数据 Redis-cluster 拓扑图: 架构演变及 cap 理论: 单机 Redis 属于 cp 模型. Re ...

  10. 四川软件人才网:打造四川最专业的IT人才招聘平台

    四川软件人才网(www.tfsp.net),原名:天府软件人才网:为了更好的发展和拓展的业务需要,更名为:四川软件人才网,强力打造四川最专业的IT人才的招聘平台. 网站依托四川软件人才社区,微博,微信 ...