源码工程:
C++设计模式-行为型模式-解释器模式
https://download.csdn.net/download/qq_40788199/85782166码云:
C++设计模式-行为型模式-解释器模式
https://gitee.com/gongguixing/c-design-mode.git
解释器(Interpreter)模式的定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
这里提到的文法和句子的概念同编译原理中的描述相同,“文法”指语言的语法规则,而“句子”是语言集中的元素。例如,汉语中的句子有很多,“我是中国人”是其中的一个句子,可以用一棵语法树来直观地描述语言中的句子。
解释器模式是一种类行为型模式,其主要优点如下。
解释器模式的主要缺点如下。
解释器模式常用于对简单语言的编译或分析实例中,为了掌握好它的结构与实现,必须先了解编译原理中的“文法、句子、语法树”等相关概念。
1) 文法
文法是用于描述语言的语法结构的形式规则。没有规矩不成方圆,例如,有些人认为完美爱情的准则是“相互吸引、感情专一、任何一方都没有恋爱经历”,虽然最后一条准则较苛刻,但任何事情都要有规则,语言也一样,不管它是机器语言还是自然语言,都有它自己的文法规则。例如,中文中的“句子”的文法如下。
〈句子〉::=〈主语〉〈谓语〉〈宾语〉 〈主语〉::=〈代词〉|〈名词〉 〈谓语〉::=〈动词〉 〈宾语〉::=〈代词〉|〈名词〉 〈代词〉你|我|他 〈名词〉7大学生I筱霞I英语 〈动词〉::=是|学习
注:这里的符号“::=”表示“定义为”的意思,用“〈”和“〉”括住的是非终结符,没有括住的是终结符。
2) 句子
句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由“文法”推导出。例如,上述文法可以推出“我是大学生”,所以它是句子。
3) 语法树
语法树是句子结构的一种树型表示,它代表了句子的推导结果,它有利于理解句子语法结构的层次。图 1 所示是“我是大学生”的语法树。

有了以上基础知识,现在来介绍解释器模式的结构就简单了。解释器模式的结构与组合模式相似,不过其包含的组成元素比组合模式多,而且组合模式是对象结构型模式,而解释器模式是类行为型模式。
1. 模式的结构
解释器模式包含以下主要角色。

- #ifndef IEXPRESSION_H
- #define IEXPRESSION_H
-
- #include <string>
- #include <vector>
- using namespace std;
-
- // 抽象表达式(Abstract Expression)角色
- // 定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
-
- class IExpression
- {
- public:
- virtual ~IExpression() {}
-
- virtual bool interpret(const string &info) = 0;
- };
-
- #endif // IEXPRESSION_H
- #ifndef TERMINALEXPRESSION_H
- #define TERMINALEXPRESSION_H
-
- #include "iexpression.h"
-
- // 终结符表达式(Terminal Expression)角色
- // 是抽象表达式的子类,用来实现文法中与终结符相关的操作,
- // 文法中的每一个终结符都有一个具体终结表达式与之相对应。
-
- class TerminalExpression : public IExpression
- {
- public:
- TerminalExpression(const vector<string> &infos);
-
- bool interpret(const string &info) override;
-
- private:
- vector<string> mInfos;
- };
-
- #endif // TERMINALEXPRESSION_H
- #include "terminalexpression.h"
- #include <algorithm>
-
- TerminalExpression::TerminalExpression(const vector<string> &infos)
- : mInfos(infos)
- {
-
- }
-
- bool TerminalExpression::interpret(const string &info)
- {
- auto it = std::find(mInfos.begin(), mInfos.end(), info);
- return it == mInfos.end() ? false : true;
- }
- #ifndef ANDEXPRESSION_H
- #define ANDEXPRESSION_H
-
- #include "iexpression.h"
-
- // 非终结符表达式(Nonterminal Expression)角色
- // 也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,
- // 文法中的每条规则都对应于一个非终结符表达式。
-
- class AndExpression : public IExpression
- {
- public:
- AndExpression(IExpression * pCity, IExpression * pPerson);
-
- bool interpret(const string &info) override;
-
- // 字符串分割
- size_t split(const string &info, vector<string> &infos);
-
- private:
- IExpression * pCity;
- IExpression * pPerson;
- };
-
- #endif // ANDEXPRESSION_H
- #include "andexpression.h"
-
- AndExpression::AndExpression(IExpression *pCity, IExpression *pPerson)
- {
- this->pCity = pCity;
- this->pPerson = pPerson;
- }
-
- bool AndExpression::interpret(const string &info)
- {
- vector<string> infos;
- if (split(info, infos) != 2)
- {
- return false;
- }
-
- return pCity->interpret(infos.at(0)) && pPerson->interpret(infos.at(1));
- }
-
- size_t AndExpression::split(const string &info, vector<string> &infos)
- {
- // 分割字符
- string spStr = "的";
- // 起始位置
- size_t pos = 0;
-
- while (true)
- {
- size_t npos = info.find(spStr, pos);
- // 未找到分割字符
- if (npos == string::npos)
- {
- infos.push_back(info.substr(pos, info.size() - 1));
- break;
- }
- // 截取字符串
- string str = info.substr(pos, npos);
- // 定义下个位置
- pos = npos + spStr.size();
- infos.push_back(str);
- }
-
- return info.size();
- }
- #ifndef CONTEXT_H
- #define CONTEXT_H
-
- #include "andexpression.h"
- #include "terminalexpression.h"
-
- // 环境(Context)角色
- // 通常包含各个解释器需要的数据或是公共的功能,
- // 一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
-
- class Context
- {
- public:
- Context();
- ~Context();
-
- void freeRide(const string &info);
-
- private:
- vector<string> mCitys;
- vector<string> mPersons;
-
- IExpression * pCity;
- IExpression * pPerson;
-
- IExpression * pCityPerson;
- };
-
- #endif // CONTEXT_H
- #include "context.h"
- #include <iostream>
-
- Context::Context()
- {
- mCitys = {"广州", "珠海"};
- mPersons = {"老人", "妇女", "儿童"};
-
- pCity = new TerminalExpression(mCitys);
- pPerson = new TerminalExpression(mPersons);
- pCityPerson = new AndExpression(pCity, pCityPerson);
- }
-
- Context::~Context()
- {
- delete pCityPerson;
- delete pCity;
- delete pPerson;
- }
-
- void Context::freeRide(const string &info)
- {
- if (pCityPerson->interpret(info))
- {
- std::cout << "您是" << info << ",您本次乘车免费!" << std::endl;
- }
- else
- {
- std::cout << info << ",您不是免费人员,本次乘车扣费2元!" << std::endl;
- }
- }
- #include <iostream>
- #include "context.h"
-
- int main()
- {
- //设置字符集,终端正常显示中文
- system("chcp 65001");
-
- // 解释器(Interpreter)模式的定义:
- // 给分析对象定义一个语言,并定义该语言的文法表示,
- // 再设计一个解析器来解释语言中的句子。
- // 也就是说,用编译语言的方式来分析应用中的实例。
- // 这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
-
- Context * pBus = new Context();
- pBus->freeRide("珠海的老人");
- pBus->freeRide("珠海的年轻人");
- pBus->freeRide("广州的妇女");
- pBus->freeRide("广州的儿童");
- pBus->freeRide("山东的儿童");
-
- delete pBus;
-
- return 0;
- }
前面介绍了解释器模式的结构与特点,下面分析它的应用场景。