解释器模式(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. java大数据最全课程学习笔记(3)--HDFS 简介及操作

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages 目录 HDFS 简介及操作 HDFS概述 HDFS产出背景及定义 HDFS优缺点 HDFS组成架构 HDFS文件块大小 ...

  2. Cyber Security - Palo Alto Firewall Security Zones

    Firewall Security Zones Zones: The foundational aspect of every Firewall. Police network traffic Enf ...

  3. 数据结构C语言实现----出队伍操作

    1.创建一个队列时,空队列中队首和队尾相同,但不是NULL,队首后面挂的元素才是NULL 2.打印队列时,对于链队列,不能把指针加一来找到下一个数据,因为链表地址不连续,需要复制一条链表,不断往后遍历 ...

  4. (int) 与 Convert.ToInt32()

    ((xEnd - xStart) / newSize) + 1 = 172.99999999 int Width = (int)((xEnd - xStart) / newSize) + 1;  = ...

  5. 如何用redis做缓存

    redis缓存 在互联网应用中经常需要用redis来缓存热点数据. redis数据在内存,可以保证数据读取的高效,接近每秒数十万次的吞吐量 减少下层持久层数据库读取压力,像mongodb,每秒近千次读 ...

  6. 浅析MySQL中change与modify的区别

    MySQL版本 show variables like 'version'; 表结构 desc student; 修改表 例如:修改表student的name字段,将varchar(10)修改为var ...

  7. 搭建NFS Server

    搭建NFS Server Kubetrain K8S在线直播培训,内推机会 不满意可无条件退款 现在就去广告 #背景 Kubernetes 对 Pod 进行调度时,以当时集群中各节点的可用资源作为主要 ...

  8. 常见的HTTP返回状态值

    200 (成功) 服务器已成功处理了请求. 通常,这表示服务器提供了请求的网页. 301 (永久移动) 请求的网页已永久移动到新位置. 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自 ...

  9. XML--概念、约束、解析

    概念 XML:可扩展标记语言 HTML:超文本标记语言 两者的区别: 1.语法结构类似,单语法要求不同 HTML不区分大小写,XML严格区分大小写 在HTML中,有时不严格,如果上下文清楚地显示出段落 ...

  10. for循环运用,三角形

    用for循环打出三角形.倒三角形.金字塔.99乘法表 三角形: 打出如图三角形,分析行数与*个数的关系,用for循环 for(var i=0;i<5;++i){//i表示行数 var str=& ...