设计模式——解析器模式(Interpreter)

意图:

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.

 

适用性:

1、当有一个语言需要解释执行,并且你可以把该语言中的句子表示为一个抽象的语法树时,可使用解释器模式.而当存在以下情况时,该模式的效果最好:

2、该文法简单,对于复杂的文法,文法的类层次变得庞大而无法管理.此时,语法分析程序生成器这样得工具时更好得选择。它们无需构建抽象语法树即可解释表达式,这样可以节省空间而且还可以节省时间;

3、效率不是一个关键的问题,最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先把他们转换成另外一种形式.例如:正则表达式通常被转换成状态机。但即使在这种情况下,转换器仍可用解释器模式实现,该模式仍是有用的.


结构图:

设计模式——解析器模式(Interpreter)_第1张图片



Interpreter设计模式中的几种角色:

AbstractExpression:

声明一个抽象的Interpret方法,抽象语法树中所有的节点都必须实现该抽象方法。

 

TerminalExpression:

实现和语法中末端符号相关的Interpret方法。

在每个句子的末端符号中均需要一个TerminalExpression实例。

 

NonterminalExpression:

另外一个实现了AbstractExpression 接口的类,用来处理语法树中非末端节点的语法。它含有下一个AbstractExpression(s)的引用,调用它每个子节点的Interpret方法。

 

Context:

Interpreter方法所需要的信息的容器,该信息对Interpreter而言全局可见。充当几个AbstractExpresssion 实例之间的通讯频道。

 

PatternClient:

构建或者接收一个抽象语法书的实例。对于一个特定的句子而言,语法树往往由若干个TerminalExpressions NonterminalExpression组成。PatterClient在合适的context下,调用Interpret方法。

 

Interpreter模式的应用场合是interpreter模式应用中的难点,只有满足业务规则频繁变化,且类似的模式不断重复出现,并且容易抽象为语法规则的问题才适合使用Interpreter模式。

 

使用Interpreter模式来表示文法规则,从而可以使用面向对象技巧来方便地扩展文法。

   

Interpreter模式比较适合简单的文法表示,对于复杂的文法表示,Interpreter模式会产生比较大的类层次结构,这时候就不应该采用Interpreter模式了。

 

效率不是一个Interpreter关心的关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。例如:正则表达式通常被转换成状态机。但即使在这种情况下,如果效率不是一个关键问题,转换器仍可用Interpreter模式实现,该模式仍是有用的。

 

代码:

以下是一个运用Interpretor模式完成罗马数字到阿拉伯数字转换的例子,其中用到了后面将讲到的Template Method模式,注意,该程序只能处理万以下的数值转换

#include 
#include 
using namespace std;

// "Context"
class Context
{
private:
    string input;
    int output;

public:
    Context( const string& input ) : input(input), output(0) { }
    friend class Expression;
    friend ostream& operator << (ostream& os, Context& context)
    {
        return os << context.output;
    }
};

// "AbstractExpression"
class Expression
{
public :
    // Template Method
    void Interpret( Context& context )
    {
        string& input = context.input;
        int& output = context.output;

        if (0 == input.length()) return;
        if (input.find(Nine()) == 0)
        {
            output += 9 * Multiplier();
            input = input.substr(2, input.length() - 2);
        }
        else if (input.find(Four()) == 0)
        {
            output += 4 * Multiplier();
            input = input.substr(2, input.length() - 2);
        }
        else if (input.find(Five()) == 0)
        {
            output += 5 * Multiplier();
            input = input.substr(1, input.length() - 1);
        }
        while (input.find(One()) == 0)
        {
            output += Multiplier();
            input = input.substr(1, input.length() - 1);
        }
    }

    virtual const char* One() = 0;
    virtual const char* Four() = 0;
    virtual const char* Five() = 0;
    virtual const char* Nine() = 0;
    virtual int Multiplier() = 0;
};

// Thousand checks for the Roman Numeral M
// "TerminalExpression"
class ThousandExpression : public Expression
{
    // Methods
    const char* One() { return "M"; }
    const char* Four(){ return " "; }
    const char* Five(){ return " "; }
    const char* Nine(){ return " "; }
    int Multiplier() { return 1000; }
};

// Hundred checks C, CD, D or CM
// "TerminalExpression"
class HundredExpression : public Expression
{
    // Methods
    const char* One() { return "C"; }
    const char* Four(){ return "CD"; }
    const char* Five(){ return "D"; }
    const char* Nine(){ return "CM"; }
    int Multiplier() { return 100; }
};

// Ten checks for X, XL, L and XC
// "TerminalExpression"
class TenExpression : public Expression
{
    // Methods
    const char* One() { return "X"; }
    const char* Four(){ return "XL"; }
    const char* Five(){ return "L"; }
    const char* Nine(){ return "XC"; }
    int Multiplier() { return 10; }
};

// One checks for I, II, III, IV, V, VI, VII, VIII, IX
// "TerminalExpression"
class OneExpression : public Expression
{
    // Methods
    const char* One() { return "I"; }
    const char* Four(){ return "IV"; }
    const char* Five(){ return "V"; }
    const char* Nine(){ return "IX"; }
    int Multiplier() { return 1; }
};

int main()
{
    string roman("MCMXXVIII");
    Context context(roman);

    // Build the ''''parse tree''''
    Expression* exp[] = {
        new ThousandExpression(), new HundredExpression(),
        new TenExpression(), new OneExpression()};
    vector v_exp(exp, exp + sizeof(exp) / sizeof(Expression*));
    vector::iterator it = v_exp.begin();
    for (; it != v_exp.end(); it++)
    {
        (*it)->Interpret(context);
        delete (*it);
    }

    cout << roman.c_str() << "=" << context << endl;
}

相关模式:

Composite模式:抽象语法树是一个复合模式的实例

Flyweight模式:说明了如何在抽象语法树中共享终结符

Iterator模式:解释器可用一个迭代器遍历该结构

Visitor模式:可用来在一个类中维护抽象语法树中各节点的行为



你可能感兴趣的:(设计模式)