解释器模式(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. 为什么大家都在用Fiddler?

    在我们做接口测试的时候,经常需要验证发送的消息是否正确,或者在出现问题的时候,查看手机客户端发送给server端的包内容是否正确,就需要用到抓包工具.常用的抓包工具有fiddler.wireshark ...

  2. OSCP Learning Notes - Post Exploitation(3)

    Post-Exploit Password Attacks 1. Crack using the tool - john (Too slow in real world) Locate the roc ...

  3. Ethical Hacking - NETWORK PENETRATION TESTING(7)

    Gaining Access to encrypted networks Three main encryption types: 1. WEP 2.WPA 3.WPA2 WEP Cracking W ...

  4. 集训作业 洛谷P1101 单词方阵

    这个题的长度真的有点长,我直接放图片吧 这个题又是一个和谐的搜索,找到yizhong的y就开始8面搜索,遇见正确的字母就继续搜索,不正确就果断放弃,果然又是一个和谐的搜索呢. #include< ...

  5. ztree : 增删改功能demo与自定义DOM功能demo的结合

    最近有个项目要用ztree,需要用ztree自带的功能(增删改),也需要自定义DOM的功能(置顶). ztree的demo里有增删改的demo,也有自定义DOM的demo,但没有两者结合的. 所以我把 ...

  6. HTTP请求方式及常见问题

    请求方式 当前HTTP一共有八种方式.有三种是有HTTP1.0提供,剩余五种则是有HTTP1.1提供 常见问题 啥是OPTIONS?有啥作用 是浏览器对复杂跨域请求的一种处理方式,在真正发送请求之前, ...

  7. 题解 洛谷 P3247 【[HNOI2016]最小公倍数】

    题意可以转化为是否能找一条从\(u\)到\(v\)的路径,经过的边的\(a\)和\(b\)的最大值恰好都是询问所给定的值. 若只有\(a\)的限制,可以将询问离线,对边和询问都从小到大排序,然后双指针 ...

  8. 题解 洛谷 P6142 【[USACO20FEB]Delegation P】

    和赛道修建类似,先对\(k\)进行二分,将最值问题转化为判定问题. 在判定一个\(k\)是否合法时,贪心去考虑,一个节点下面的若干条链在合并时,一条链肯定和另一条使它合并后恰好满足长度限制的链合并最优 ...

  9. DJANGO-天天生鲜项目从0到1-006-首页-内容展示

    本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...

  10. AI大厂算法测试心得:人脸识别关键指标有哪些?

    仅仅在几年前,程序员要开发一款人脸识别应用,就必须精通算法的编写.但现在,随着成熟算法的对外开放,越来越多开发者只需专注于开发垂直行业的产品即可. 由调查机构发布的<中国AI产业地图研究> ...