【设计模式】解释器模式

news2024/11/20 0:40:55

文章目录

  • 1.解释器模式定义
  • 2.解释器模式的角色
  • 3.解释器模式实战案例
    • 3.1.场景说明
    • 3.2.结构类图
    • 3.3.代码实现
  • 4.解释器模式优缺点
  • 5.解释器模式适用场景
  • 6.解释器模式总结

在这里插入图片描述

主页传送门:💁 传送

1.解释器模式定义

       解析器模式(Interpreter Pattern)是一种按照规定语法进行解析的方案,在现在项目中使用较少,其定义如下:

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

       即:给定一门语言,定义他的文法的表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
       其通用类图如下:
在这里插入图片描述

2.解释器模式的角色

解释器模式所涉及到的角色有:

  • Context 解释器上下文环境类
    用来存储解释器的上下文环境,包含解释器之外的一些全局信息,比如需要解释的文法等
  • AbstractExpression 解释器抽象类,抽象表达式
    这个接口为抽象语法树中所有节点所共享
  • TerminalExpression 解释器具体实现类,终结符表达式
    实现与文法中的终结符相关联的解释操作
    一个句子中的每个终结符需要该类的一个实例
  • NonterminalExpression 解释器具体实现类,非终结符表达式
    对文法中的每一个规则R :: = RR…R都需要一个NonterminalExpression类。
    为从R到R的每个符号都维护一个AbstractExpression类型的实例变量。
    为文法中的非终结符实现解释操作。解释一般要递归地调用表示R到R的那些对象的解释操作。
  • Client 客户
    构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
    调用解释操作。

3.解释器模式实战案例

3.1.场景说明

实现音乐解释器,定义一套规则:

T表示速度,以毫秒为单位;

O 表示音阶, O1 表示低音阶, O2 表示中音阶, O3 表示高音阶;

P 表示休止符;

C D E F G A B 表示 “Do-Re-Mi-Fa-So-La-Ti”;

音符长度1表示一拍,2表示二拍,0.5表示半拍,0.25表示四分之一拍;

所有字母和数字都要用半角空格分开。

3.2.结构类图

       使用解释器模式来实现的结构图如下所示::
在这里插入图片描述

3.3.代码实现

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;
 
//演奏内容类
class PlayContext {
public:
    void SetText(string _text) {
        text = _text;
    }
    string GetText() {
        return text;
    }
private:
    string text;
};
 
//抽象表达式类
class Expression {
public:
    virtual void Excute(string key, string value) = 0;
    void Interpret(PlayContext* context) {
        if (context->GetText().length() == 0)
            return;
        else {
            vector<string> vs;
            stringstream ss(context->GetText());  //使用字符串构造一个stringstream
            //按空格分割字符串
            string buf;
            while (ss >> buf)
                vs.push_back(buf);
            //解释前两个字符串
            Excute(vs[0], vs[1]);
            //拼接剩下的字符串
            string tmp;
            vs.erase(vs.begin(), vs.begin() + 2);
            for (vector<string>::iterator it = vs.begin(); it != vs.end(); it++) {
                tmp += *it;
                if (it < vs.end() - 1)
                    tmp += " ";
            }
            //更新字符串
            context->SetText(tmp);
        }
    }
};
 
//音符类
class Note :public Expression {
public:
    void Excute(string key, string value) {
        string note = " ";
        switch (key[0]) {
        case'C':
            note = "1"; break;
        case'D':
            note = "2"; break;
        case'E':
            note = "3"; break;
        case'F':
            note = "4"; break;
        case'G':
            note = "5"; break;
        case'A':
            note = "6"; break;
        case'B':
            note = "7"; break;
        default:
            break;
        }
        cout << note << " ";
    }
};
 
//音阶类
class Scale :public Expression {
public:
    virtual void Excute(string key, string value) {
        string scale = " ";
        switch (value[0])
        {
        case'1':
            scale = "低音"; break;
        case'2':
            scale = "中音"; break;
        case'3':
            scale = "高音"; break;
        default:
            break;
        }
        cout << scale << " ";
    }
};
 
//音速类
class Speed : public Expression
{
public:
    void Excute(string key, string value)
    {
        int v = stoi(value);
        if (v < 500)
            cout << "快速 ";
        else if (v > 1000)
            cout << "慢速 ";
        else
            cout << "中速 ";
    }
};
 
int main()
{
    PlayContext context;
    cout << "上海滩: " << endl;
    context.SetText("T 600 O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5");
    Expression* expression = NULL;
    while (context.GetText().length() > 0)
    {
        char str = context.GetText()[0];
        switch (str)
        {
        case'O':
            expression = new Scale; break;
        case'T':
            expression = new Speed; break;
        case'C':
        case'D':
        case'E':
        case'F':
        case'G':
        case'A':
        case'B':
        case'P':
            expression = new Note; break;
        default:
            break;
        }
        expression->Interpret(&context);
        delete expression;
    }
    cout << endl;
    return 0;
}

运行结果:
在这里插入图片描述

4.解释器模式优缺点

解释器模式的优点主要包括:

  1. 灵活性高:解释器模式可以通过定义语言的文法和解释器,灵活地扩展和改变语言的解析和执行规则。
  2. 易于扩展:通过增加新的终结符表达式和非终结符表达式,可以很容易地扩展语言的表达能力。
  3. 可读性好:解释器模式将语言的语法规则抽象成了类的结构,使得语法规则更加易于理解和维护。

解释器模式的缺点主要包括:

  1. 执行效率低:由于解释器模式需要递归地解释和执行表达式,因此在处理复杂表达式时可能会导致性能问题。
  2. 可利用场景比较少:解释器模式通常适用于特定领域的语言解析和执行,因此其应用场景相对较少。
  3. 对于复杂的文法比较难维护:当语言的语法规则变得复杂时,解释器模式的实现和维护难度也会相应增加。

总的来说,解释器模式适用于需要解析和执行特定领域语言的场景,但在使用时需要权衡其优缺点,并根据实际需求进行选择和设计。

5.解释器模式适用场景

解释器模式适用于以下场景:

  1. 需要定义一个语言,并且为该语言定义一个解释器,用于解析和执行该语言中的句子。
  2. 某些特定类型的问题发生频率足够高,需要专门构建一个解释器来处理这些问题。例如,日志处理、配置文件解析等。

在这些场景下,解释器模式可以帮助我们构建一个灵活、可扩展的语言解析和执行系统,使得语言的解析和执行更加高效、可靠。

6.解释器模式总结

     解释器模式是一种用于构建解释器的设计模式,它允许我们定义一个语言的文法规则,并构建一个解释器来解析和执行该语言中的句子。通过将语言的语法规则抽象成类的结构,解释器模式使得语言的解析和执行更加灵活、可扩展。在使用解释器模式时,需要注意其执行效率、可维护性等方面的问题,并根据实际需求进行选择和设计。

如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏 🙌一起讨论
你的支持就是我✍️创作的动力! 💞💞💞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1120359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我国跨境电商行业研究报告(2022)

我国跨境电商行业研究报告 我国跨境电商规模突飞猛进&#xff0c;2022年进出口规模超2万亿元&#xff0c;2023年上半年跨境电商出口8210亿元&#xff0c;增长19.9%。全国跨境电商主体已超10万家&#xff0c;近年来涌现出一批上市公司&#xff0c;以及广州希音等全球独角兽企业。…

Java后端模拟面试 题集④

1.你先作个自我介绍吧 面试官您好&#xff0c;我叫张睿超&#xff0c;来自湖南长沙&#xff0c;大学毕业于湖南农业大学&#xff0c;是一名智能科学与技术专业的统招一本本科生。今天主要过来面试贵公司的Java后端开发工程师岗位。 大学里面主修的课程是Java、Python、数字图…

AD20 ~PCB封装库的制作

1、打开“51单片机最小系统”的工程文件。 2、创建PCB库文件&#xff1a;单击“文件”菜单&#xff0c;选择“新的”选项中的“库”选项&#xff0c;再选择“PCB 元件库”&#xff0c;进入元件PCB封装的编辑界面。 3、保存PCB库文件&#xff1a;选择“文件”菜单&#xff0c;选…

OpenCV实战——使用YOLO进行目标检测

OpenCV实战——使用YOLO进行目标检测 0. 前言1. YOLO 模型简介2. 基于 YOLO 实现目标检测3. 完整代码相关链接 0. 前言 在本节中&#xff0c;我们将使用 YOLO 算法执行目标检测。目标检测是计算机视觉中的一项常见任务&#xff0c;借助深度学习技术&#xff0c;我们可以实现高…

Vue虚拟节点和渲染函数

1.虚拟节点 虚拟节点&#xff08;dom&#xff09;本质上就是一个普通的JS对象&#xff0c;用于描述视图的界面结构 2.渲染函数render()&#xff1a;接收一个 createElement()函数创建的VNode Vue.component("board", {render: function(createElement) {return cr…

025-第三代软件开发-实现需求长时间未操作返回登录界面

第三代软件开发-实现需求长时间未操作返回登录界面 文章目录 第三代软件开发-实现需求长时间未操作返回登录界面项目介绍实现需求长时间未操作返回登录界面实现思路用户操作监控QML 逻辑处理 关键字&#xff1a; Qt、 Qml、 QTimer、 timeout、 eventFilter 项目介绍 欢迎…

【Linux】文件权限、目录权限、掩码、粘滞位以及相关指令

文章目录 Linux权限两种用户Linux权限管理三个问题:什么是权限呢?三种角色是什么:那么为什么存在所属组呢? 文件类型和访问权限&#xff08;事物属性&#xff09;a) 文件类型b)基本权限 文件权限值的表示方法文件访问权限的相关设置方法a)chmodb)chownc)chgrp 权限掩码d)umas…

第87步 时间序列建模实战:LSTM回归建模

基于WIN10的64位系统演示 一、写在前面 这一期&#xff0c;我们介绍大名鼎鼎的LSTM回归。 同样&#xff0c;这里使用这个数据&#xff1a; 《PLoS One》2015年一篇题目为《Comparison of Two Hybrid Models for Forecasting the Incidence of Hemorrhagic Fever with Renal…

UVM-什么是UVM方法学

概念简介 百度对UVM的解释如下&#xff1a; 通用验证方法学&#xff08;Universal Verification Methodology, UVM&#xff09;是一个以SystemVerilog类库为主体的验证平台开发框架&#xff0c;验证工程师可以利用其可重用组件构建具有标准化层次结构和接口的功能验证环境 UVM…

C/C++文件操作————写文件与读文件以及通讯录的改进 (保姆级教学)

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂。 目录 1.前言 2.写文件函数与读文件函数 …

打印新闻标题,使用封装get、set方法,打印前15个字符串

package day21; import java.util.ArrayList; import java.util.Collections;/*** author monian* Wo yi wu ta,wei shou shu er!*/ public class Homework01 {SuppressWarnings({"all"})public static void main(String[] args) {News news1 new News("新冠确…

Typora的相关配置(Typora主题、字体、快捷键、习惯)

Typora的相关配置(Typora主题、字体、快捷键、习惯) 文章目录 Typora的相关配置(Typora主题、字体、快捷键、习惯)[toc]一、主题配置二、字体配置查看字体名称是否可以被识别&#xff1a;如果未能正确识别&#xff1a; 三、习惯配置四、快捷键配置更改提供的功能的快捷键&#…

【学习笔记】win11 时间显示秒

【学习笔记】windows 11 时间显示秒 原本一直用着 windows 10 的系统&#xff0c;点击右下角的托盘时钟&#xff0c;可以看到当前的秒数&#xff0c;平时拿来粗略的计时&#xff0c;看时间非常的方便&#xff0c;现在换成了 windows 11 的系统&#xff0c;点击右下角的托盘时钟…

如何处理前端本地存储和缓存?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

【Qt控件之QTabBar】介绍及使用

概述 QTabBar类提供了一个选项卡栏&#xff0c;例如用于选项卡对话框。 QTabBar非常简单易用&#xff0c;它使用预定义的形状绘制选项卡&#xff0c;并在选择选项卡时发出信号。它可以被子类化以调整外观和感觉。Qt还提供了一个实现好的QTabWidget。 每个选项卡具有一个tabT…

图——邻接表

图的邻接表表示法&#xff08;有向图&#xff09; 实现绿色的有向图 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <corecrt_malloc.h>#define Max 100//顶点数量最大值typedef struct ArcNode {//边信息int VNode_index;//顶点下标ArcNode…

MySQL索引全解:从理论到实践,打造高效查询的指南

文章目录 索引的数据结构Hash表有序数组树 详细聊聊BTreeBTree的特点树的度&#xff08;宽度&#xff09;可以很大叶子节点存储数据叶子节点双向指针记录 聚簇索引聚簇索引的优点聚簇索引的缺点 覆盖索引如何利用覆盖索引 普通索引与唯一索引的选择查询更新change bufferchange…

从入门到精通,30天带你学会C++【第八天:函数及洛谷精选题目讲解】(学不会你找我)

目录 Everyday English 前言 函数 洛谷 P5736 【深基7.例2】质数筛 分析题意 思路点拨 AC代码 AC截图 结尾 Everyday English Winners never quit! 胜者永不言弃&#xff01; 前言 这节课我们来学习函数&#xff0c;虽然我断更了几周&#xff0c;但我还是要把最…

三十六、【进阶】show profiles分析

1、profiles &#xff08;1&#xff09;详情 可以帮助清楚的展现&#xff0c;每一条SQL语句的执行耗时&#xff0c;以及时间都耗费到哪里去了 &#xff08;2&#xff09;基础语句 2、查看是否支持profiles mysql> select have_profiling; ------------------ | have_prof…

【LeetCode力扣】234 快慢指针 | 反转链表 | 还原链表

目录 1、题目介绍 2、解题思路 2.1、暴力破解法 2.2、快慢指针反转链表 1、题目介绍 原题链接&#xff1a; 234. 回文链表 - 力扣&#xff08;LeetCode&#xff09; 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1]输出&#xff1a;true 示例 2&#xff1a; 输入&am…