【愚公系列】2021年12月 二十三种设计模式(十五)-解释器模式(Interpreter Pattern)

简介: 【愚公系列】2021年12月 二十三种设计模式(十五)-解释器模式(Interpreter Pattern)

文章目录

前言

一、解释器模式(Interpreter Pattern)

二、使用步骤

角色

示例

总结

优点

缺点

使用场景

前言

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。


提示:以下是本篇文章正文内容,下面案例可供参考


一、解释器模式(Interpreter Pattern)

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


解释器模式提供了评估语言的语法或表达式的方式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被广泛地应用在 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来充当环境角色就足够了。


示例

image.png

命名空间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代表航程。

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.

总结

优点

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

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

3、易于实现简单文法。


缺点

1、可利用场景比较少;

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

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

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


使用场景

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

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

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


相关文章
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
2月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)
|
2月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
5月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
6月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
6月前
|
设计模式 SQL Java
【设计模式】抖音一面:你不知道解释器模式?
【设计模式】抖音一面:你不知道解释器模式?
51 1
|
6月前
|
设计模式 Go
[设计模式 Go实现] 行为型~解释器模式
[设计模式 Go实现] 行为型~解释器模式
|
6月前
|
设计模式 存储 Java
小谈设计模式(28)—解释器模式
小谈设计模式(28)—解释器模式
|
6月前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
49 1
|
6月前
|
设计模式 存储 SQL
【设计模式系列笔记】解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一种语言的文法,并且建立一个解释器来解释该语言中的句子。在Java中,解释器模式通常用于实现编程语言解释器、正则表达式解释器等。
59 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    42
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78