【重读设计模式】解释器模式

来源:互联网 发布:中国农业大学网络管理 编辑:程序博客网 时间:2024/06/04 19:15

解释器模式,应该是23个设计模式中最少人使用,最难的模式了。使用场景是如此的少,几乎相当于设计了一门语言,绝大多数时候的系统都没有必要做这种设计,但是在某些特定的场合下,解释器模式还是很有必要的。下面就来具体看看使用最少的模式,最难的模式的解释器模式。


定义:给定一种语言,并定义它文法的一种表示,同时定义一个解释器,使用该解释器来解释该表示在语言中的句子。

定义解释:任何一种语言都有自己的语言规范,定义语句应该怎样写,我们称这种规范为文法,语句的编写规范就是该语言的文法。编写了相应的代码,如何让语言去理解用户编写的代码语句,这就需要一个解释器,解释器就是将用户的代码翻译成机器可以理解的指令,使用了解释器解释代码,就相应将不同的语言的代码翻译成了统一的机器代码,交给cpu执行。这样将的话,解释器模式就是(1)定义一种规范(用户输入的字符串)(2)定义一个解释该规范的函数,(3)使用该函数将用户输入的“代码”解释成机器代码并执行。


使用场景:

(1)一些重复发生的问题,比如 整数的四则运算。

(2)有一个简单的语法规则,比如正则表达式,比如sql语句。

解释器模式就是处理,某些有简单的语法规则,并且会重复发生的问题的设计模式。 


类图:


解释器模式的结构

  • 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
  • 终结符表达式:实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。                                
  • 非终结符表达式:文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
  • 环境角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。


例子:

各位数的加减法运算是一个简单的例子,个位数的加减运算可以是1+2+3+4,也可以是2+3-4-5+6,这是一个简单的语法规则并且重复发生的问题。我们可以将它看成一个表达式,那么如何计算任何一个表达式的结果呢。


设计:

我们知道表达式运算是有一定的规则的,规则就是+-两边必须是数字,两个数字之间也必须是+-,最后的数字之后没有+-,最前的数字之前没有+-。现在我们将+-成为操作符,把数字成为操作数,同时把操作符左右两边的操作数称为左操作数和右操作数。这里数字就是终结符表达式,运算符就是非终结符表达式。


实现:

//============================================================================
// Name        : interpreter.cpp
// Author      : tester
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;


class CContext
{
public:
CContext(const string& str)
{
}
};


class CExpression
{
public:
virtual ~CExpression(){};
virtual int interpreter(const CContext& context) = 0;
};


class CPlusExpression : public CExpression
{
public:
CPlusExpression(CExpression* leftexpr, CExpression* rightexpr)
{
m_leftexpr = leftexpr;
m_rightexpr = rightexpr;
}


int interpreter(const CContext& content)
{
return m_leftexpr->interpreter(content)+m_rightexpr->interpreter(content);
}


private:
CExpression* m_leftexpr;
CExpression* m_rightexpr;
};


class CMinusExpression : public CExpression
{
public:
CMinusExpression(CExpression* leftexpr, CExpression* rightexpr)
{
m_leftexpr = leftexpr;
m_rightexpr = rightexpr;
}


int interpreter(const CContext& content)
{
return m_leftexpr->interpreter(content)-m_rightexpr->interpreter(content);
}


private:
CExpression* m_leftexpr;
CExpression* m_rightexpr;
};


class CNumberExpression : public CExpression
{
public:
CNumberExpression(char ch)
{
m_number = 0;
m_number = ch-'0';
}


int interpreter(const CContext& context)
{
return m_number;
}
private:
int m_number;
};


int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!


CNumberExpression* num1 = new CNumberExpression('9');
CNumberExpression* num2 = new CNumberExpression('8');
CPlusExpression* plusexpr = new CPlusExpression(num1, num2);
CMinusExpression* minusexpr = new CMinusExpression(plusexpr, new CNumberExpression('5'));


CContext context("111");
int result = minusexpr->interpreter(context);
cout << result << endl;
return 0;
}


结果:

!!!Hello World!!!
12


总结:解释器模式描述的是一种将自定义的一种规则的代码解释成相应的真实代码的过程,在该例子中,本来的表达式是9+8-5,我们通过将其解释成9+5是第一个表达式,该表达式有三个元素,+是非终结表达式,9和8是总结表达式,9+8被解释成了17,然后使用17作为一个终结表达式和5这个终结表达式进行-操作,从而得到12这个结果。



0 0
原创粉丝点击