C++实现设计模式---解释器模式 (Interpreter Pattern)
解释器模式 (Interpreter Pattern)
解释器模式 是一种行为型设计模式,它提供了一个语言的语法表示,并定义了一个解释器来处理这个语言的语法。通过解释器模式,可以实现对特定语法或表达式的解析和执行。
意图
- 定义一种语言的文法,并提供一个解释器来处理语言中的语句。
- 通过解析和解释特定语言的表达式,实现灵活的扩展和动态计算。
使用场景
- 需要解析特定语法或表达式:
- 如计算器的表达式求值。
- 语言规则相对简单,且可扩展:
- 规则可以使用组合模式表达。
- 需要对用户输入的语句进行解析并执行:
- 如脚本语言解析器。
参与者角色
- 抽象表达式 (Expression)
- 定义解释操作的接口。
- 终结符表达式 (TerminalExpression)
- 实现与文法中的终结符相关的解释操作。
- 非终结符表达式 (NonTerminalExpression)
- 实现文法中的非终结符的解释操作,通常是其他表达式的组合。
- 上下文 (Context)
- 包含解释器需要的全局信息。
- 客户端 (Client)
- 构建文法树,并通过调用解释器来解释表达式。
示例代码
以下代码展示了解释器模式的实现,用于解析和计算简单的数学表达式。
#include <iostream>
#include <string>
#include <memory>
#include <unordered_map>
// 抽象表达式
class Expression {
public:
virtual ~Expression() = default;
// 解释方法
virtual int interpret(const std::unordered_map<std::string, int>& context) const = 0;
};
// 终结符表达式:变量
class VariableExpression : public Expression {
private:
std::string name;
public:
explicit VariableExpression(std::string name) : name(std::move(name)) {}
int interpret(const std::unordered_map<std::string, int>& context) const override {
auto it = context.find(name);
if (it != context.end()) {
return it->second; // 返回变量的值
}
throw std::runtime_error("变量未定义: " + name);
}
};
// 终结符表达式:常量
class ConstantExpression : public Expression {
private:
int value;
public:
explicit ConstantExpression(int value) : value(value) {}
int interpret(const std::unordered_map<std::string, int>& context) const override {
return value; // 返回常量值
}
};
// 非终结符表达式:加法
class AddExpression : public Expression {
private:
std::shared_ptr<Expression> left;
std::shared_ptr<Expression> right;
public:
AddExpression(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
: left(std::move(left)), right(std::move(right)) {}
int interpret(const std::unordered_map<std::string, int>& context) const override {
return left->interpret(context) + right->interpret(context); // 加法操作
}
};
// 非终结符表达式:减法
class SubtractExpression : public Expression {
private:
std::shared_ptr<Expression> left;
std::shared_ptr<Expression> right;
public:
SubtractExpression(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
: left(std::move(left)), right(std::move(right)) {}
int interpret(const std::unordered_map<std::string, int>& context) const override {
return left->interpret(context) - right->interpret(context); // 减法操作
}
};
// 客户端代码
int main() {
// 构建表达式: (x + 10) - y
auto x = std::make_shared<VariableExpression>("x");
auto y = std::make_shared<VariableExpression>("y");
auto constant = std::make_shared<ConstantExpression>(10);
auto addExpr = std::make_shared<AddExpression>(x, constant); // x + 10
auto subtractExpr = std::make_shared<SubtractExpression>(addExpr, y); // (x + 10) - y
// 上下文
std::unordered_map<std::string, int> context = {{"x", 5}, {"y", 3}};
// 解释表达式
std::cout << "表达式结果: " << subtractExpr->interpret(context) << "
"; // 输出结果: 12
return 0;
}
代码解析
1. 抽象表达式 (Expression)
- 定义了解释操作的接口,所有具体表达式类都需要实现此接口。
class Expression {
public:
virtual ~Expression() = default;
virtual int interpret(const std::unordered_map<std::string, int>& context) const = 0;
};
2. 终结符表达式
VariableExpression
:表示变量,解释时从上下文中获取变量的值。ConstantExpression
:表示常量,解释时直接返回常量值。
class VariableExpression : public Expression {
int interpret(const std::unordered_map<std::string, int>& context) const override {
return context.at(name);
}
};
3. 非终结符表达式
AddExpression
和SubtractExpression
实现了抽象表达式接口。- 它们通过组合其他表达式实现复杂的语法结构。
class AddExpression : public Expression {
int interpret(const std::unordered_map<std::string, int>& context) const override {
return left->interpret(context) + right->interpret(context);
}
};
4. 客户端代码
- 客户端通过组合表达式构建语法树,并传入上下文解析表达式。
优缺点
优点
- 扩展性强:
- 可以轻松扩展新的表达式类型。
- 语法清晰:
- 将语言的语法结构化,易于维护和扩展。
- 灵活性:
- 通过组合模式,可以灵活构造复杂的语法。
缺点
- 性能开销:
- 每个表达式都是一个对象,可能导致较大的内存开销。
- 复杂性高:
- 对于复杂语法,类的数量可能急剧增加。
- 适用范围有限:
- 适用于简单语法,复杂语言解析时不适合。
适用场景
- 需要解释语言或语法:
- 如编译器、计算器等。
- 需要灵活扩展表达式的语法规则:
- 通过组合表达式动态扩展语法。
总结
解释器模式通过定义语言的文法和解释器,提供了一种解析和执行表达式的机制。它适用于简单语言或语法的解析场景,但对于复杂语言解析可能并不适合。