解释器模式(Interpreter Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/415 访问。

解释器模式属于行为型模式,给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

解释器模式提供了评估语言的语法或表达式的方式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被广泛地应用在 SQL 解析、符号处理引擎等领域。

角色:

1、抽象表达式(Expression)

声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口一般是一个Interpret()方法,称做解释操作;

2、终结符表达式(Terminal Expression)

实现了抽象表达式角色所要求的接口,一般是Interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式;

3、非终结符表达式(Nonterminal Expression)

文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式;

4、环境(Context)

这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

示例:

命名空间InterpreterPattern中包含IWord抽象表达式接口,4个终结符表达式和1个非终结符表达式,Instruction类代表1条完整的指令,Semicolon类分隔左右两边的指令,Interpreter类充当环境类以构建表达式树并调用抽象表达式接口的解释方法Interpret。本案例尝试通过控制一次飞机的起飞至降落的过程来讲述解释器模式的使用方法。以下是我们要解释的指令:

340.00 10.00 taxing 1.00;
27.00 120.00 takeoff 1.00;
90.00 350.00 fly 30.00;
180.00 400.00 cruise 230.00;
50.00 320.00 fly 20.00;
320.00 110.00 landing 3.00;
120.00 10.00 taxing 3.00;

以上是我们要解释的所有7条指令,所有指令在同一行上,分号后是没有换行的,因为文章排版需要加了换行。以第1行为例解释每个参数的含义。340.00代表航向,10.00代表空速,taxing代表飞机的运动类型,1.00代表航程。

namespace InterpreterPattern
public interface IWord {

    string Interpret();

}

定义抽象表达式接口IWord,包含一个Interpret方法。

public sealed class Course : IWord {

    private double _course = 0;

    public Course(double course) {
this._course = course;
} public string Interpret() {
return $"heading:{_course}°,";
} }

航向解释类Course,终结符表达式。

public sealed class Speed : IWord {

    private double _speed = 0;

    public Speed(double speed) {
this._speed = speed;
} public string Interpret() {
return "speed:" + _speed.ToString() + "kn,";
} }

空速解释类Speed,终结符表达式。

public sealed class Movement : IWord {

    private string _movement = String.Empty;

    public Movement(string movement) {
this._movement = movement;
} private Dictionary<string, string> _movements = new Dictionary<string, string> {
{"taxing","taxing on the runway"},
{"takeoff","take off from the runway"},
{"fly","flying in the sky"},
{"cruise","navigate a cruise"},
{"landing","landing on the runway"},
}; public string Interpret() {
return "movement:" + _movements[_movement] + ",";
} }

运动解释类Movement,终结符表达式。

public sealed class Voyage : IWord {

    private double _voyage = 0;

    public Voyage(double voyage) {
this._voyage = voyage;
} public string Interpret() {
return "voyage:" + _voyage.ToString() + "km.";
} }

航程解释类Voyage,终结符表达式。

public sealed class Semicolon : IWord {

    private IWord _left = null;
private IWord _right = null; public Semicolon(IWord left, IWord right) {
this._left = left;
this._right = right;
} public string Interpret() {
return _left.Interpret() + Environment.NewLine + _right.Interpret();
} }

分号解释类Semicolon,非终结符表达式。

public sealed class Instruction : IWord {

    private IWord _course = null;
private IWord _speed = null;
private IWord _movement = null;
private IWord _voyage = null; public Instruction(IWord course, IWord speed, IWord movement, IWord voyage) {
this._course = course;
this._speed = speed;
this._movement = movement;
this._voyage = voyage;
} public string Interpret() {
return _course.Interpret() +
_speed.Interpret() +
_movement.Interpret() +
_voyage.Interpret();
} }

由非终结符表达式分隔开的所有终结符表达式构成一条完整的指令Instruction类,这个类包含一个解释方法Interpret。

public class Interpreter {

    private IWord _word = null;

    private Instruction _instruction = null;

    public string Interpret(string instruction) {
string[] instrucs = instruction.Split(';'); foreach(var word in instrucs) {
if(word.Trim() == "") break;
string[] words = word.Split(' '); _instruction = new Instruction(new Course(double.Parse(words[0])),
new Speed(double.Parse(words[1])),
new Movement(words[2]),
new Voyage(double.Parse(words[3]))); if(_word == null) {
_word = _instruction;
} else {
_word = new Semicolon(_word, _instruction);
}
} return _word.Interpret();
} }

解释类Interpreter,充当环境类,此类最终构建一个表达式树并完成所有指令的解释动作。

public class Program {

    private static Interpreter _interpreter = new Interpreter();

    public static void Main(string[] args) {
string instruction = "340.00 10.00 taxing 1.00;" +
"27.00 120.00 takeoff 1.00;" +
"90.00 350.00 fly 30.00;" +
"180.00 400.00 cruise 230.00;" +
"50.00 320.00 fly 20.00;" +
"320.00 110.00 landing 3.00;"+
"120.00 10.00 taxing 3.00;"; Console.WriteLine(_interpreter.Interpret(instruction));
Console.ReadKey();
} }

以上是调用方的代码,以下是这个案例的输出结果:

heading:340°,speed:10kn,movement:taxing on the runway,voyage:1km.
heading:27°,speed:120kn,movement:take off from the runway,voyage:1km.
heading:90°,speed:350kn,movement:flying in the sky,voyage:30km.
heading:180°,speed:400kn,movement:navigate a cruise,voyage:230km.
heading:50°,speed:320kn,movement:flying in the sky,voyage:20km.
heading:320°,speed:110kn,movement:landing on the runway,voyage:3km.
heading:120°,speed:10kn,movement:taxing on the runway,voyage:3km.

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/415 访问。

1、可扩展性比较好、灵活;

2、增加了新的解释表达式的方式;

3、易于实现简单文法。

缺点:

1、可利用场景比较少;

2、对于复杂的文法比较难维护;

3、解释器模式会引起类膨胀;

4、解释器模式采用递归调用方法。

使用场景:

1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树;

2、一些重复出现的问题可以用一种简单的语言来进行表达;

3、一个简单语法需要解释的场景。

C#设计模式之15-解释器模式的更多相关文章

  1. [设计模式] 15 解释器模式 Interpreter

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对解释器模式是这样说的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.如果一种特定类 ...

  2. Java进阶篇设计模式之九----- 解释器模式和迭代器模式

    前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解 ...

  3. Java设计模式学习记录-解释器模式

    前言 这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以 ...

  4. Java设计模式之九 ----- 解释器模式和迭代器模式

    前言 在上一篇中我们学习了行为型模式的责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern).本篇则来学习下行为型模式的两个模式, 解 ...

  5. java设计模式-----16、解释器模式

    概念: Interpreter模式也叫解释器模式,是行为模式之一,它是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法.简单地说,Interpreter模式是 ...

  6. 大话设计模式Python实现-解释器模式

    解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: #!/usr/ ...

  7. 设计模式之GOF23解释器模式

    解释器模式Interpreter -是一种不常用的设计模式 -用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计 -当我们需要开发一种新的语言时,可以考虑使用解释器 ...

  8. 面向对象设计模式之Interpreter解释器模式(行为型)

    动机:在软件构建过程中 ,如果某一特定领域的问题比较复杂,类似的模式不断重复出现,如果使用普通的编程方式来实现将面临非常频繁的变化.在这种情况下,将特定领域的问题表达为某种语法规则的句子,然后构建一个 ...

  9. 设计模式之笔记--解释器模式(Interpreter)

    解释器模式(Interpreter) 定义 解释器模式(Interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 类图 描述 Expr ...

  10. 《Java设计模式》之解释器模式

    解释器模式是类的行为模式.给定一个语言之后,解释器模式能够定义出其文法的一种表示,并同一时候提供一个解释器. client能够使用这个解释器来解释这个语言中的句子. 解释器模式的结构 以下就以一个示意 ...

随机推荐

  1. Go Pentester - HTTP Servers(2)

    Routing with the gorilla/mux Package A powerful HTTP router and URL matcher for building Go web serv ...

  2. Go的100天之旅-06数组和Slice

    目录 数组 Slice 数组 Go的数组和其它语言基本上一样,是长度固定的特定类型元素组成的序列,这基本上是所有语言数组的特性.和其它语言相比差异主要在声明和初始化的写法上,下面是简单声明一个数组: ...

  3. Python 如何生成 200 个激活码

    请用 Python 如何生成 200 个激活码. 激活码的格式为asqE-9xRK-lqWU-QkMT 要求1: 使用随机生成时,生成数字概率为1/5,大写字母和小写字母概率各为2/5 要求2: 这2 ...

  4. 《Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases》论文总结

    Aurora总结 说明:本文为论文 <Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relation ...

  5. 带你上手阿里开源的 Java 诊断利器:Arthas

    本文适合有 Java 基础知识的人群. 本文作者:HelloGitHub-秦人 HelloGitHub 推出的<讲解开源项目>系列,今天给大家带来一款阿里开源的 Java 诊断利器 Art ...

  6. Oracle常见错误以及解决方法

    前言: 本博客为博主在开发中遇到的问题,为大家提供解决方法,如需转载,请注明来源,谢谢! 问题一: 第一次用PLSQL Developer连接数据库,若用sys用户登录并操作则正常,若用普通用户比如x ...

  7. 怎么理解Python迭代器与生成器?

    怎么理解Python迭代器与生成器?在Python中,使用for ... in ... 可以对list.tuple.set和dict数据类型进行迭代,可以把所有数据都过滤出来.如下:         ...

  8. 我们通常这样使用Linux弱口令检测!

    在Internet环境中,过于简单的口令是服务器面临的最大风险,对于管理员来说,即使找出这些弱口令账号是非常必要的,这样便于采取进一步的安全措施. 这里的话,弱口令检测需要用到一款密码破译软件--Jo ...

  9. .net core 发布程序命令(自带运行环境)

    dotnet publish -c Release -r linux-x64 --self-contained true

  10. windy数(数位dp)

    https://www.luogu.com.cn/blog/virus2017/shuweidp https://www.luogu.com.cn/problem/P2657 #include < ...