20 【行为型】解释器模式 - Interpreter

通过解释器模式实现四则运算,具体要求:
输入表达式,比如a+b+c-d

基本介绍:
1、解释器模式(interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
2、解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题;
3、在编译原理中,一个算数表达式通过语法分析器形成词法单元,词法分析器和语法分析器,都是解释器;

应用场景:
1、编译器,正则表达式,浏览器(解析html显示)、机器人等等
2、正则表达式就是它的一种应用,解释器为正则表达式定义了一个文法,如何表示一个特定的正则表达式,以及如何解释这个正则表达式;

原理类图:


角色及职责说明:
1、context:环境角色,还有解释器之外的全局信息;
2、abstractExpression:抽象表达式,声明一个抽象的解释操作,这个方法为抽象语法树中所有的节点所共享;
3、terminalExpression:为终结符表达式,实现与文法中的终结符相关的解释操作;
4、NonTerminalExpression:为非终结表达式,为文法中的非终结符实现解释操作;
5、说明:输入context和expression通过用户输入即可;
/*
 * @Description: 
 * @Remark: 
 * @Author: whl
 * @博客园: https://www.cnblogs.com/cnwhl/
 * @Date: 2021-12-29 17:21:11
 * @LastEditTime: 2021-12-30 20:15:00
 */
#include <stdlib.h>
#include <iostream>
#include <string>
#include <map>

using namespace std;

class Context;

/**
 * @description: 抽象表达式类
 * @Remark: 声明一个抽象解释操作,这个接口为抽象语法树中所有的接口所共享
 */
class AbstractExpression
{
public:
    virtual int Interpret(Context* pContext, int& index) = 0;
};

/**
 * @description: 上下文信息类
 * @Remark: 提供设置表达式接口和计算接口
 */
class Context
{
public:
    void SetExpression(char c,AbstractExpression* pExpr)
    {
        m_mapExpr[c] = pExpr;
    }

    // a + b - c + d
    int Caculate(string expression){
        m_res = 0;
        m_expr = expression;

        for(int i = 0; i < expression.size(); i++){
            string expr;
            switch(expression[i])
            {
                case '+':
                {
                    auto it = m_mapExpr.find('+');
                    m_res = it->second->Interpret(this,i);
                    break;
                }      
                case '-':
                {
                    auto it = m_mapExpr.find('-');
                    m_res = it->second->Interpret(this,i);
                    break;
                }
                    
                default:
                {
                    expr = expression[i];
                    m_res += atoi(expr.c_str());
                    break;
                }           
            }
        }

        return m_res;
    }

    int GetRes(){
        return m_res;
    }

    int GetNum(int index){
        char sz[4] = { 0 };
        sz[0]  = m_expr[index];
        return atoi(sz);
    }

private:
    map<char,AbstractExpression*> m_mapExpr;
    string m_expr;
    int m_res;
};

/**
 * @description: 具体表达式实现类
 * @Remark: 实现加法操作
 */
class AddExpression: public AbstractExpression
{
public:
    int Interpret(Context* pContext, int& index){    
        cout << "Add Expression " << endl;
        return pContext->GetRes() + pContext->GetNum(++index);
    }
};

/**
 * @description: 具体表达式实现类
 * @Remark: 实现减法操作
 */
class SubExpression: public AbstractExpression
{
public:
    int Interpret(Context* pContext, int& index){
        cout << "Sub Expression " << endl;
        return pContext->GetRes() - pContext->GetNum(++index);
    }
};

/**
 * @description: 计算表达式的函数
 * @Remark: 为了跟上述类做对比
 * @param {string} expression 表达式
 * @return int
 */
// a + b - c + d
int Caculate(string expression)
{
    int res = 0;
    for(int i = 0; i < expression.size(); i++){
        string expr;
        switch(expression[i])
        {
            case '+':
                expr = expression[++i];
                res += atoi(expr.c_str());
                break;
            case '-':
                expr = expression[++i];
                res -= atoi(expr.c_str());
                break;
            default:
                expr = expression[i];
                res += atoi(expr.c_str());
                break;
        }
    }

    return res;
}

int main()
{
    int res = Caculate("1+2-3+4");
    cout << "res = " << res << endl;

    AddExpression* pAddExpr = new AddExpression();
    SubExpression* pSubExpr = new SubExpression();
    Context* pContext = new Context();

    pContext->SetExpression('+',pAddExpr);
    pContext->SetExpression('-',pSubExpr);

    res = pContext->Caculate("1+2-3+4");
    cout << "res = " << res << endl;

    return 0;
}
注意事项及优缺点:
1、可能会引起类的膨胀,递归调用方法,导致复杂,效率低下;
2、优点:
容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法。也比较容易实现文法,因为定义抽象语法树中各个节点的类的实现大体类似,这些类都易于直接编写;
3、缺点:
解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如:语法分析程序、编译器生成器 来处理;






posted @ 2021-12-30 20:23  sfwhl  阅读(113)  评论(0)    收藏  举报