• 【设计模式】解释器模式



    在这里插入图片描述

    主页传送门:💁 传送

    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 
    #include 
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

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

    4.解释器模式优缺点

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

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

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

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

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

    5.解释器模式适用场景

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

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

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

    6.解释器模式总结

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

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

  • 相关阅读:
    【Hack The Box】windows练习-- Silo
    【C++内存管理】
    day11力扣打卡
    C语言-手写Map(全功能)
    Win11的两个实用技巧系列之如何关闭文字热门搜索、任务栏上的应用
    ELK 企业级日志分析系统
    【单片机】18-红外线遥控
    结构体指针的引入
    使用ControlCAN.dll收发报文功能实现诊断仪与硬件的UDS报文交互
    跨域 —— 反向代理配置
  • 原文地址:https://blog.csdn.net/hm973046/article/details/133971080