解释器模式(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. Ubuntu14.04 安装VMware tools

    Ubuntu14.04 安装VMware tools 方法一: 1. 在VMware 11(个人的测试环境为vm 11版本)下安装Ubuntu镜像:ubuntu-14.04.1-desktop-amd ...

  2. threadLocal源码土话解说

    前言 废话不多说,先了解什么是threadLocal,下面是threadLocal类的说明注释, 这段话大致(猜的)意思是,改类为线程提供了一个局部变量,但是呢,这个变量和普通的变量又有所不同,怎么不 ...

  3. win7下建立docker共享文件夹

    前言 建立本机(win7)和VirtualBox中docker虚拟机的共享文件夹,注:下面的命令都是以root身份运行的,使用sudo -i切换到root身份,如无法切换,请自行在命令前加上sudo命 ...

  4. java并发编程[持续更新]

    目录 java并发编程 1.常用类介绍 Semaphore 2.名词解释 2.1 线程安全 2.2 可重入锁和不可重入锁 java并发编程 1.常用类介绍 Semaphore Semaphore 类是 ...

  5. redis pipelined 示例

    redis 常用的数据类型 有序集合(sort set).无序集合 (set),hashMap redis pipelined 示例 List<Object> list = jedisTe ...

  6. 硬核干货:5W字17张高清图理解同步器框架AbstractQueuedSynchronizer

    前提 并发编程大师Doug Lea在编写JUC(java.util.concurrent)包的时候引入了java.util.concurrent.locks.AbstractQueuedSynchro ...

  7. vue-resource(搬运)

    一.vue-resource特点vue-resource插件具有以下特点: 1. 体积小vue-resource非常小巧,在压缩以后只有大约12KB,服务端启用gzip压缩后只有4.5KB大小,这远比 ...

  8. OFD呼之欲来、来之跚跚,谁之罪?

    软件国产化的浪潮势不可挡,美国逼得逾甚,我们压迫感逾强,唯有奋起直追方慰平生之志. 在板式文档领域,pdf已成为国际标准,亦可称为美国标准:它在该领域一枝独秀,已形成一览众山小之势! pdf出道20余 ...

  9. 递归-N皇后问题

    // // #include <stdio.h> /*可以用回溯,但是我已经不太熟悉回溯了!!!!!!!!呜呜呜 * */ #include <iostream> #inclu ...

  10. Linux中配置端口转发(反向代理)

    在conf.d目录下建一个文件, 以conf为结尾(如果没有conf.d目录,就自己新建一个) server { listen 80; server_name 127.0.0.1; #这个IP是你服务 ...