Charpter27 解释器模式

Posted yb-blogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Charpter27 解释器模式相关的知识,希望对你有一定的参考价值。

解释器模式简介

解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示解释语言中的句子

解释器模式需要解决的是,如果一个特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决问题。比如说正则表达式就是利用给解释器来模式实现的。

通常当有一个语言需要解释执行,并且你可将改语言中的句子表示为一个抽象语法树时,可实用解释器模式。

解释器模式的好处是可以很容易地改变和扩展文法,因为该模式实用累的表示文法准则,你可实用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中的各个节点的类的实现大体类似。这些类都易于直接编写。

解释器的不足之处,解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理

解释器模式UML类图

技术图片

 

技术图片

 

 

C++代码实现

具体解释模式的内Interpt的的细节可忽略,不同的解释器为达到解释的目的,要根据一定的规则进行解释。具体规则与此设计模式无关。

// PlayContext 类
#ifndef _PLAYCONTEXT_HPP
#define _PLAYCONTEXT_HPP

#include<string>

using namespace std;

class PlayContext{
public:
    PlayContext(const string& str):context(str){}
    string getContext(){
        return context;
    }
    void setContext(string str){
        context = str;
    }
private:
    string context;
};

#endif

 

//  Expression类
#ifndef _EXPRESSION_HPP
#define _EXPRESSION_HPP

#include"playcontext.hpp"

class Expression{
public:
    void interpret(PlayContext* context){
        if(context && context->getContext().size() != 0){
            string playKey = context->getContext().substr(0,1);           
            context->setContext(context->getContext().substr(1));
            string::size_type pos; // get the index postion after stod function call.
            double playValue = stod(context->getContext(),&pos);//transfer the front substr to double;
            excute(playKey, playValue);
            if(pos+1 < context->getContext().size()){
                context->setContext(context->getContext().substr(pos+1));
            }
            else{
                context->setContext("");
            }
        }
        else{
            //do nothing;
        }
    }

    virtual void excute(string key, double value) = 0;
};

#endif

 

// Note类
#ifndef _NOTE_HPP
#define _NOTE_HPP

#include<iostream>
#include"expression.hpp"

using namespace std;

class Note : public Expression{
public:
    virtual void excute(string key, double val) override { 
        string note;
        if("C" == key ){
            note = "1";
        }
        else if("D" == key){
            note = "2";
        }
        else if("E" == key){
            note = "3";
        }
        else if("F" == key){
            note = "4";
        }
        else if("G" == key){
            note = "5";
        }
        else if("A" == key){
            note = "6";
        }
        else if("B" == key){
            note = "7";
        }
        else{
            // do nothing
        }
        cout << note << " ";
    }

};


#endif

 

//Scale类
#ifndef _SCALE_HPP
#define _SCALE_HPP

#include<iostream>
#include"expression.hpp"

using namespace std;

class Scale : public Expression{
public:
    virtual void excute(string key, double val)override{
        string scale;
        switch((int)val){
            case 1:
                scale = "base";
                break;
            case 2:
                scale = "mediant";
                break;
            case 3:
                scale = "treble";
                break;
            default:
                break;
        }
        cout << scale << " ";
    }
};

#endif

 

// MyException类,只是为了异常处理,与设计模式无关
#ifndef _MYEXCEPTION_HPP
#define _MYEXCEPTION_HPP

#include<exception>
#include<string>
#include<cstring>

class MyException : public std::exception{
public:
    MyException(const std::string& str){
        char pre[] = "no this charactor ‘";
        strcpy(val,pre);
        if(str.size() < sizeof(val)-strlen(pre)){
            strcat(val,str.c_str());
        }
        else{
            strncat(val,str.c_str(),sizeof(val) - strlen(pre) -2);
        }
        strcat(val,"");
    }
    virtual const char* what(){
        return val;
    }
private: 
    char val[100]; 
};

#endif

 

// 客户端代码
#include<iostream>
#include"playcontext.hpp"
#include"note.hpp"
#include"scale.hpp"
#include"myexception.hpp"

using namespace std;

int main(){
    PlayContext* context = new PlayContext(
        "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 "
        );
    try{
        while(context && (context->getContext()!="") && context->getContext().size() != 0){
            string str = context->getContext().substr(0, 1);
            Expression* exp  = nullptr;
            if("O" == str){
                exp = new Scale();
            }
            else if("C" == str || "D" == str || "E" == str || "F" == str
                    || "G" == str || "A" == str || "B"  == str || "P" == str){
                exp = new Note();
            }
            else{
                throw(new MyException(str));
            }
            if(exp){
                exp->interpret(context);
            }
            
        }
        
    }catch(MyException*e){
        cout << e->what()<<endl;
        getchar();
    }
    catch(...){
        cout << "Other exception occurs"<<endl;
        getchar();
    }

    getchar();
    return 0;
}

 

以上是关于Charpter27 解释器模式的主要内容,如果未能解决你的问题,请参考以下文章

Charpter13 建造者模式

Charpter04 开放-封闭原则

设计模式(27)-----解释器模式

centos-7 charpter one

有趣的 C++ 代码片段,有啥解释吗? [复制]

“反应堆模式”及其应用的简单解释[关闭]