设计模式C++实现25:解释器模式(Interpreter)

news2024/11/25 13:46:45

部分内容参考大话设计模式第27章;本实验通过C++语言实现。   

一 基本原理 

意图:给定一个语言,定义其文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

上下文:如果业务规则频繁变化,类似的模式不断重复出现,这种特定类型的变化发生的频率足够高,但效率不是关键。

能否抽象并表示一种简单的语法规则,这种语法能将各种变化表述为一种简单语言的句子,以应对这种频繁的变化? 

解释器模式静态类图 

 AbstractExpression:声明一个抽象的解释操作,这个接口为抽象语法树中所有节点共享。

TerminalExpression:实现语法中的终结符的解释操作,一个句子中的每个终结符都需要该类的一个实例。

NonterminalExpression:语法中的每个规则R::=R1,R2,…,Rn都需要一个这样的类;R1,…,Rn中每个符号都需要该类的一个实例;实现语法中非终结符的解释操作,解释一般需要递归地调用R1,…,Rn的解释操作。

Context:解释器之外的全局信息。

Client:构建表示语法中一个特定的句子的抽象语法树,该抽象语法树由TerminalExpression和NonterminalExpression的实例装配而成;调用AbstractExpression的解释操作(Interpret)

测试代码:

#include <iostream>
#include <list>
#include <mutex>
#include <map>
#include <string>

using namespace std;
class Context{
public:
    string input;

    string getInput() const;
    void setInput(const string &value);

    string output;
    string getOutput() const;
    void setOutput(const string &value);
};
string Context::getInput() const
{
return input;
}

void Context::setInput(const string &value)
{
input = value;
}

string Context::getOutput() const
{
return output;
}

void Context::setOutput(const string &value)
{
output = value;
}
class AbstractExpression{
public:
    virtual void Interpret(Context *context) = 0;
};

class TerminalExpression : public AbstractExpression{


    // AbstractExpression interface
public:
    void Interpret(Context *context)
    {
        (void)(context);
        cout << "终端解释器" << endl;
    }
};
class NonterminalExpression : public AbstractExpression{


    // AbstractExpression interface
public:
    void Interpret(Context *context)
    {
        (void)(context);
        cout << "非终端解释器" << endl;
    }
};

int main(void)
{
    Context *c = new Context();
    list<AbstractExpression*> mylist;
    mylist.push_back(new TerminalExpression());
    mylist.push_back(new NonterminalExpression());
    mylist.push_back(new TerminalExpression());
    mylist.push_back(new TerminalExpression());

    list<AbstractExpression*>::iterator it;

    for(it = mylist.begin();it != mylist.end();it++){
        AbstractExpression *exp = *it;
        exp->Interpret(c);
    }
    cout << "--end--" << endl;
    return 0;
}


 运行结果:

终端解释器

非终端解释器

终端解释器

终端解释器

--end--

 二 音乐解释器实现

 测试代码:

#include <iostream>
#include <list>
#include <mutex>
#include <map>
#include <string>

using namespace std;
//演奏内容类
class PlayContext{
public:
    string text;
    string playText;
    string getText() const;
    void setText(const string &value);
    string getPlayText() const;
    void setPlayText(const string &value);
};
string PlayContext::getPlayText() const
{
return playText;
}

void PlayContext::setPlayText(const string &value)
{
playText = value;
}

string PlayContext::getText() const
{
return text;
}

void PlayContext::setText(const string &value)
{
text = value;
}
//表达式类
class Expression{
public:
    void Interpret(PlayContext *context){
        if(context->playText.length() == 0){
            return;
        }else{
            string playKey = context->playText.substr(0,1);
            context->playText = context->playText.substr(2);
            double platValue = stod(context->playText.substr(0,context->playText.find(" ")));
            context->playText = context->playText.substr(context->playText.find(" ") + 1);
            this->Excute(playKey,platValue);
        }
    }
    virtual void Excute(string key,double value) = 0;
};
//音符类
class Note:public Expression{
    // Expression interface
public:
    void Excute(string key, double value)
    {
        (void)(value);
        string note = "";
        do{
            if(key == "C"){
                note = "1";
                break;
            }
            if(key == "D"){
                note = "2";
                break;
            }
            if(key == "E"){
                note = "3";
                break;
            }
            if(key == "F"){
                note = "4";
                break;
            }
            if(key == "G"){
                note = "5";
                break;
            }
            if(key == "A"){
                note = "6";
                break;
            }
            if(key == "B"){
                note = "7";
                break;
            }

        }while(0);
        cout << note << " ";
    }
};
//音阶类
class Scale:public Expression{


    // Expression interface
public:
    void Excute(string key, double value)
    {
        (void)(key);
        string scale = "";
        switch ((int)(value)) {
        case 1:
            scale = "低音";
            break;
        case 2:
            scale = "中音";
            break;
        case 3:
            scale = "高音";
            break;
        default:
            cout << "这里不对" << value << endl;
            break;
        }
        cout << scale << " ";
    }
};

//音速
class Speed:public Expression
{


    // Expression interface
public:
    void Excute(string key, double value)
    {
        string speed;
        if(value < 500){
            speed = "快速";
        }else if(value >= 1000){
            speed = "慢速";
        }else{
            speed = "中速";
        }
        cout << speed << " ";
    }
};

int main(void)
{
    PlayContext *c = new PlayContext();
    cout << "上海滩" << endl;
    c->playText = "T 500 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 G 1 C 0.5 E 0.5 D 3 ";
    Expression *exp;
    while(c->playText.length() > 0){
        //cout << c->playText << endl;
        string str = c->playText.substr(0,1);
        if(str.length() == 0){
            cout << "解析完毕" << endl;
            break;
        }
        if(str == "O"){
            exp = new Scale();
        }else if(str == "T"){
            exp = new Speed();
        }else if(str == "C" || str == "D"
                 || str == "E"|| str == "F"
                 || str == "G"|| str == "A"|| str == "B"){
            exp = new Note();
        }
        exp->Interpret(c);
    }
    cout << endl << "--end--" << endl;
    return 0;
}

运行结果:

上海滩
中速 中音 3 5 6 3 5 2 3 5 6 高音 1 中音 6 5 1 3 2 
--end--

小结

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

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

相关文章

Netty核心组件创建源码浅析

pipeline&#xff0c;Handler&#xff0c; HandlerContext创建源码剖析 源码解析目标 Netty中的ChannelPipeline&#xff0c;ChannelHandler和ChannelHandlerContext是核心组件&#xff0c;从源码解析来分析 Netty是如何设计三个核心组件分析Netty是如何创建和协调三个组件三…

LQB05 数码管动态扫描,显示字符串

1、蓝桥杯51单片机开发板的数码管是共阳数码管&#xff1b; 需要注意段码表的推导。 掌握推导段码表。 2、stcisp软件的数码管代码&#xff0c;是共阴的模式&#xff0c;注意取反的话&#xff0c;如何实现&#xff1f; 3、定时器动态扫描的思路&#xff1b; 4、注意动态扫描的时…

golang入门笔记——测试

测试类型&#xff1a; 单元测试&#xff1a; 规则&#xff1a; 1.所有测试文件以_test.go结尾 2.func Testxxx&#xff08;*testing.T&#xff09; 3.初始化逻辑放到TestMain中 运行&#xff1a; go test [flags][packages]Go语言中的测试依赖go test命令。 go test命令是一…

(考研湖科大教书匠计算机网络)第六章应用层-第四节:域名系统DNS

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;DNS概述二&#xff1a;层次域名结构&#xff08;1&#xff09;概述&#xff08;2&#xff09;顶级域名分类&#xff08;3&#xff09;因特网命名空…

「SAP」ABAP模块学习需要了解什么?快收下这份ABAP技术栈指南【附技能树】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计专业大二本科在读&#xff0c;阿里云社区专家博主&#xff0c;华为云社区云享专家&#xff0c;CSDN SAP应用技术领域新兴创作者。   在学习工…

1. MacOs Dart环境安装

前置材料&#xff1a;需要安装dart的Mac设备, 一颗会用搜索引擎的聪明大脑一步步讲一下homebrew的安装流程我个人安装时遇到的情况 大家做个参考 如果你遇到的问题和我的不一样可以来这里 homebrew快速安装指引 可入群咨询首先, 我其实是安装过homebrew的网上常见的dart安装命令…

2003 -Cant connect to MySql server on IP地址 (10060)----在docker安装的MySQL连接阿里云服务器

MySQL配置 这个问题是因为在数据库服务器中的mysql数据库中的user的表中没有权限(也可以说没有用户)&#xff0c;下面将记录我遇到问题的过程及解决的方法。 在搭建完LNMP环境后用Navicate连接出错 遇到这个问题首先到mysql所在的服务器上用连接进行处理 0、docker exec -it m…

界面控件DevExpress WinForm——轻松构建类Visual Studio UI(二)

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

嵌入式常用知识

12、并发和并行的区别&#xff1f; 最本质的区别就是&#xff1a;并发是轮流处理多个任务&#xff0c;并行是同时处理多个任务。 你吃饭吃到一半&#xff0c;电话来了&#xff0c;你一直到吃完了以后才去接&#xff0c;这就说明你不支持并发也不支持并行。 你吃饭吃到一半&…

推荐5款实用小工具,第五款更是小白最爱

作为一个黑科技软件爱好者&#xff0c;电脑里肯定是不会缺少这方面的东西&#xff0c;今天的5款实用小工具闪亮登场了。 1.磁盘空间分析——SpcaeSniffer SpcaeSniffer是一款可视化硬盘空间占用布局大小的查询工具&#xff0c;软件体积小巧&#xff0c;使用简单。软件可对所需…

Android Studio翻译插件推介(Translation)

前言 Android Studio翻译插件适合英语水平不太好的程序员&#xff08;比如&#xff1a;我&#xff09;&#xff0c;最常用的翻译插件Translation和AndroidLocalize&#xff0c;本文主要讲解Translation&#xff0c;亲测可用。 先看看效果&#xff1a;这里是Android的API,任意选…

apache、iis设置301教程(适用虚拟主机)

当前提供教程是通过重写规则实现301,目前西部数码主机面板已经开发"301转向"功能可快捷设置&#xff1a; 如果部署了https访问&#xff0c;请忽略此教程&#xff0c;部署https的网站请参考&#xff1a;https://www.west.cn/faq/list.asp?unid1419 进入业务管理-虚…

单通道说话人语音分离——Conv-TasNet(Convolutional Time-domain audio separation Network)

单通道说话人语音分离——Conv-TasNet模型(Convolutional Time-domain audio separation Network) 参考文献&#xff1a;《Conv-TasNet: Surpassing Ideal Time-FrequencyMagnitude Masking for Speech Separation》 1.背景 在真实的声学环境中&#xff0c;鲁棒的语音处理通常…

【蓝桥杯每日一题】差分算法

&#x1f34e; 博客主页&#xff1a;&#x1f319;披星戴月的贾维斯 &#x1f34e; 欢迎关注&#xff1a;&#x1f44d;点赞&#x1f343;收藏&#x1f525;留言 &#x1f347;系列专栏&#xff1a;&#x1f319; 蓝桥杯 &#x1f319;我与杀戮之中绽放&#xff0c;亦如黎明的花…

银河麒麟V10桌面版系统将用户开发Qt界面程序添加为开机自启动

银河麒麟V10桌面版系统将用户开发Qt界面程序添加为开机自启动 银河麒麟V10桌面版系统允许用户开发自己的qt界面程序并将其添加为开机自启动。这样&#xff0c;每次开机后&#xff0c;用户开发的qt界面程序会自动启动&#xff0c;无需手动打开。 要将用户开发的qt界面程序添加…

走进chatGPT新一代机器人

chatGPT这款新一代对话式人工智能便在全球范围狂揽1亿名用户&#xff0c;并成功从科技界破圈&#xff0c;成为街头巷尾的谈资。chatGPT能干什么&#xff1f;打开官网https://openai.com/blog/chatgpt/ &#xff0c;完了&#xff0c;芭比Q了试下其他家的接口讲笑话写代码写解决方…

格雷码应用意义及编解码

文章目录1. 格雷码的应用意义2. 由自然数编码获得格雷码2.1 对称法实现2.2 公式法实现3. 由格雷码解码获得自然数1. 格雷码的应用意义 学过晶体管知识的朋友们都知道&#xff0c;数据位跳变就相当于硬件电路中的晶体管翻转。许多位同时跳变就相当于多个晶体管同时翻转&#xf…

【C++】STL之空间配置器 | STL总结

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;什么是空…

全球首个云渗透测试认证专家课程发布!腾讯安全领衔编制

2月20日&#xff0c;国际云安全联盟CSA发布了“云渗透测试认证专家CCPTP”课程体系&#xff0c;这是全球首个云渗透测试能力培养课程及人才认证项目&#xff0c;有效地弥补了云渗透测试认知的差距和技能人才培养的空白。腾讯安全在该项目中担任核心课程编撰单位。CSA是全球中立…

【双指针问题】LeetCode344、345、 844、283问题详解及代码实现

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…