热门问题
时间线
聊天
视角

解释器模式

来自维基百科,自由的百科全书

解释器模式
Remove ads

计算机编程中,解释器模式(英语:interpreter pattern),是一种设计模式[1],它规定了如何求值一个语言中的句子。基本想法是使专门计算机语言的每个符号(终结符与非终结符)都有一个。这个语言中句子的语法树合成模式的一个实例,它被用来为客户求值(解释)这个句子[2]:243

Thumb
解释器模式的UML类图

结构

Thumb
解释器模式的样例UML类图和对象图[3]

在上面的UML类图中:

  • 客户Client类提及公共的AbstractExpression接口来解释一个表达式interpret(context)
  • 终结表达式TerminalExpression类没有子表达式并且直接解释一个表达式。
  • 非终结表达式NonTerminalExpression类维护一个子表达式的容器(expressions)并且将解释请求转发给这些expressions

对象图展示了运行时交互:

  • 客户Client对象发送解释请求到抽象语法树。这个请求被沿着树结构转发到(办理于)所有对象。
  • 非终结表达式NonTerminalExpression对象(ntExpr1,ntExpr2)将请求转发到它们的子表达式。
  • 终结表达式TerminalExpression对象(tExpr1,tExpr2,…)直接的进行解释。

示例

C++

下面的例子是基于《设计模式》书中先于C++98的样例代码的C++11实现。

#include <iostream>
#include <map>
#include <cstring>

class Context;

class BooleanExp {
public:
    BooleanExp() = default;
    virtual ~BooleanExp() = default;
    virtual bool evaluate(Context&) = 0;
    virtual BooleanExp* replace(const char*, BooleanExp&) = 0;
    virtual BooleanExp* copy() const = 0;
};

class VariableExp;

class Context {
public:
    Context() :m() {}
    bool lookup(const VariableExp* key) { return m.at(key); }
    void assign(VariableExp* key, bool value) { m[key] = value; }
private:
    std::map<const VariableExp*, bool> m;
};

class VariableExp : public BooleanExp {
public:
    VariableExp(const char* name_) :name(nullptr) {
        name = strdup(name_);
    }
    virtual ~VariableExp() = default;
    virtual bool evaluate(Context& aContext) {
        return aContext.lookup(this);
    }
    virtual BooleanExp* replace( const char* name_, BooleanExp& exp ) {
        if (0 == strcmp(name_, name)) {
            return exp.copy();
        } else {
            return new VariableExp(name);
        }
    }
    virtual BooleanExp* copy() const {
        return new VariableExp(name);
    }
    VariableExp(const VariableExp&) = delete; // rule of three
    VariableExp& operator=(const VariableExp&) = delete;
private:
    char* name;
};

class AndExp : public BooleanExp {
public:
    AndExp(BooleanExp* op1, BooleanExp* op2)
        :operand1(nullptr), operand2(nullptr) {
        operand1 = op1;
        operand2 = op2;
    }
    virtual ~AndExp() = default;
    virtual bool evaluate(Context& aContext) {
        return operand1->evaluate(aContext) && operand2->evaluate(aContext);
    }
    virtual BooleanExp* replace(const char* name_, BooleanExp& exp) {
        return new AndExp(
            operand1->replace(name_, exp),
            operand2->replace(name_, exp)
        );
    }
    virtual BooleanExp* copy() const {
        return new AndExp(operand1->copy(), operand2->copy());
    }
    AndExp(const AndExp&) = delete; // rule of three
    AndExp& operator=(const AndExp&) = delete;
private:
    BooleanExp* operand1;
    BooleanExp* operand2;
};

int main() {
    BooleanExp* expression;
    Context context;
    VariableExp* x = new VariableExp("X");
    VariableExp* y = new VariableExp("Y");
    expression = new AndExp(x, y);

    context.assign(x, false);
    context.assign(y, true);
    bool result = expression->evaluate(context);
    std::cout << result << '\n';

    context.assign(x, true);
    context.assign(y, true);
    result = expression->evaluate(context);
    std::cout << result << '\n';
}

程序输出为:

0
1
Remove ads

Python

下面是Python的例子:

from abc import ABC, abstractmethod

class Context():
    def __init__(self):
        self.var_dict = {}
    def lookup(self, key):
        return (self.var_dict[key.name]
            if key.name in self.var_dict else None)
    def assign(self, key, value):
        self.var_dict[key.name] = value

class BooleanExp(ABC):
    @abstractmethod
    def evaluate(self): pass
    @abstractmethod
    def replace(self): pass
    @abstractmethod
    def copy(self): pass

class VariableExp(BooleanExp):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return f"({self.name})"
    def evaluate(self, context):
        return context.lookup(self)
    def replace(self, name, exp):
        return (exp.copy() if self.name == name
            else type(self)(self.name))
    def copy(self):
        return type(self)(self.name)

class AndExp(BooleanExp):
    def __init__(self, opd1=None, opd2=None):
        assert opd2 is not None
        self.opd1 = opd1
        self.opd2 = opd2   
    def __str__(self):
        return f"({self.opd1} and {self.opd2})"
    def evaluate(self, context):
        opd1 = self.opd1.evaluate(context)
        opd2 = self.opd2.evaluate(context)
        return opd1 and opd2 
    def replace(self, name, exp):
        opd1 = self.opd1.replace(name, exp)
        opd2 = self.opd2.replace(name, exp)
        return type(self)(opd1, opd2)
    def copy(self):
        opd1 = self.opd1.copy()
        opd2 = self.opd2.copy()
        return type(self)(opd1, opd2)

def demo():
    context = Context()
    x = VariableExp("X")
    y = VariableExp("Y")
    exp = AndExp(x, y)
    print(exp)
    context.assign(x, False)
    context.assign(y, True)
    print(exp.evaluate(context))
    context.assign(x, True)
    context.assign(y, True)
    print(exp.evaluate(context))
    z = VariableExp("Z")
    exp1 = exp.replace("X", z)
    print(exp1)
    print(exp1.evaluate(context))
    context.assign(z, False)
    print(exp1.evaluate(context))

其输出:

>>> demo()
((X) and (Y))
False
True
((Z) and (Y))
None
False
Remove ads

参见

引用

外部链接

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads