其他模式的详解:
【设计模式】桥接模式详解,如何优雅地处理不同维度的系统变化? 有原理、示例、场景、优缺点及常见面试题和答案-优快云博客
【设计模式详解】外观模式:简化复杂系统接口的大门,一键式接入,无忧使用 C++代码详解实现-优快云博客
【设计模式】功能无限,结构不变:探秘装饰器模式的神奇魔力,揭秘装饰器模式的设计精髓-优快云博客
【设计模式】适配器模式 告别接口难题,让你的代码更兼容,让你的接口不再孤单,解锁接口兼容新境界,让你的代码变得更灵活!-优快云博客
前言:
咱们一起来聊聊行为型设计模式的解释器模式。
一、原理及示例代码
解释器模式是一种行为型设计模式,它用于定义语言的文法,并且在运行时解释和执行语言中的表达式。该模式通常包含以下几个角色:
- 抽象表达式(Abstract Expression):定义了一个抽象的接口,用于解释和执行特定的语法规则。
- 终结符表达式(Terminal Expression):实现了抽象表达式接口,用于表示语言中的终结符(如变量、常量等)。
- 非终结符表达式(Non-terminal Expression):实现了抽象表达式接口,用于表示语言中的非终结符,通常由多个终结符或非终结符组成。
- 上下文(Context):包含解释器需要的全局信息,对解释器进行初始化和赋值。
下面是一个简单的 C++ 示例代码,演示了如何使用解释器模式来解释和执行简单的数学表达式:
#include <iostream>
#include <map>
// 抽象表达式
class Expression {
public:
virtual int interpret(std::map<char, int>& context) = 0;
};
// 终结符表达式
class VariableExpression : public Expression {
private:
char name;
public:
VariableExpression(char name) : name(name) {}
int interpret(std::map<char, int>& context) override {
return context[name];
}
};
// 非终结符表达式
class AddExpression : public Expression {
private:
Expression* left;
Expression* right;
public:
AddExpression(Expression* left, Expression* right) : left(left), right(right) {}
int interpret(std::map<char, int>& context) override {
return left->interpret(context) + right->interpret(context);
}
};
int main() {
// 构建解释器需要的上下文
std::map<char, int> context;
context['a'] = 5;
context['b'] = 7;
// 构建表达式:a + b
Expression* expression = new AddExpression(new VariableExpression('a'), new VariableExpression('b'));
// 执行表达式
int result = expression->interpret(context);
std::cout << "Result: " << result << std::endl;
delete expression;
return 0;
}
在上面的示例中,我们定义了抽象表达式 Expression
,终结符表达式 VariableExpression
和非终结符表达式 AddExpression
。然后,我们创建了一个上下文 context
,并构建了一个简单的数学表达式 a + b
。最后,我们执行表达式并输出结果。
二、结构图
解释器模式的结构图如下所示:
+---------------------+ +---------------------+
| AbstractExpression| | TerminalExpression|
+---------------------+ +---------------------+
| interpret() | | interpret() |
+---------------------+ +---------------------+
| |
| |
+------------------------+
|
|
+------------------+
| NonterminalExpression|
+------------------+
| interpret() |
+------------------+
在上面的结构图中,我们可以看到以下几个重要的角色:
AbstractExpression
(抽象表达式):定义了一个抽象的接口,包含interpret
方法,用于解释和执行特定的语法规则。TerminalExpression
(终结符表达式):实现了抽象表达式接口,用于表示语言中的终结符,通常包含interpret
方法来执行具体的解释。NonterminalExpression
(非终结符表达式):同样实现了抽象表达式接口,用于表示语言中的非终结符,通常由多个终结符或非终结符组成,也包含interpret
方法来执行具体的解释。
这些角色共同协作,使得解释器模式可以解释和执行特定语言的表达式。
三、使用场景
解释器模式通常在以下情况下使用:
-
当有一个简单的语法规则,并且需要解释和执行这个语法规则时,可以使用解释器模式。例如,数学表达式、逻辑表达式等都可以使用解释器模式来解释和执行。
-
当需要构建一个可以灵活扩展的语言解释器时,可以使用解释器模式。通过定义抽象表达式和具体的终结符表达式、非终结符表达式,可以轻松地扩展语言的语法规则。
下面分别给出这两种情况的C++示例代码:
场景一:数学表达式解释器
#include <iostream>
#include <map>
// 抽象表达式
class Expression {
public:
virtual int interpret(std::map<char, int>& context) = 0;
};
// 终结符表达式
class VariableExpression : public Expression {
private:
char name;
public:
VariableExpression(char name) : name(name) {}
int interpret(std::map<char, int>& context) override {
return context[name];
}
};
// 非终结符表达式
class AddExpression : public Expression {
private:
Expression* left;
Expression* right;
public:
AddExpression(Expression* left, Expression* right) : left(left), right(right) {}
int interpret(std::map<char, int>& context) override {
return left->interpret(context) + right->interpret(context);
}
};
int main() {
// 构建解释器需要的上下文
std::map<char, int> context;
context['a'] = 5;
context['b'] = 7;
// 构建表达式:a + b
Expression* expression = new AddExpression(new VariableExpression('a'), new VariableExpression('b'));
// 执行表达式
int result = expression->interpret(context);
std::cout << "Result: " << result << std::endl;
delete expression;
return 0;
}
场景二:自定义语言解释器
#include <iostream>
#include <map>
#include <string>
// 抽象表达式
class Expression {
public:
virtual int interpret(std::map<std::string, int>& context) = 0;
};
// 终结符表达式
class NumberExpression : public Expression {
private:
int value;
public:
NumberExpression(int value) : value(value) {}
int interpret(std::map<std::string, int>& context) override {
return value;
}
};
// 非终结符表达式
class VariableExpression : public Expression {
private:
std::string name;
public:
VariableExpression(const std::string& name) : name(name) {}
int interpret(std::map<std::string, int>& context) override {
return context[name];
}
};
int main() {
// 构建解释器需要的上下文
std::map<std::string, int> context;
context["x"] = 5;
context["y"] = 7;
// 构建表达式:2 * x + y
Expression* expression = new AddExpression(
new MultiplyExpression(new NumberExpression(2), new VariableExpression("x")),
new VariableExpression("y")
);
// 执行表达式
int result = expression->interpret(context);
std::cout << "Result: " << result << std::endl;
delete expression;
return 0;
}
在这两个示例中,我们分别展示了数学表达式解释器和自定义语言解释器的使用,演示了如何使用解释器模式来解释和执行特定的语法规则。
四、优缺点
解释器模式(Interpreter Pattern)的优点和缺点如下:
优点:
- 易于扩展:可以通过增加新的表达式类来扩展语言的语法规则,而不需要修改现有的代码。
- 易于实现语法解释:对于简单的语法规则,使用解释器模式可以很容易地实现语法解释和执行。
- 易于维护:将语法规则的解释功能封装在表达式类中,使得代码易于维护和理解。
缺点:
- 可能导致类膨胀:随着语法规则的复杂性增加,可能需要创建大量的表达式类,导致类的数量膨胀,使得系统变得复杂。
- 可能降低性能:解释器模式通常需要对语法规则进行解释和执行,可能会导致性能上的一些损失,特别是在处理复杂语法规则时。
总的来说,解释器模式适合用于处理简单的语法规则的解释和执行,但在处理复杂的语法规则时可能会导致类膨胀和性能损失。在选择是否使用解释器模式时,需要根据具体的场景和需求进行权衡。
------------------------------------------分界线-------------------------------------------
5
+---+
| |
| | 3 3 |---|
| | | | |
| | +---+ ----- + ---+ | |
| | + | | | | + |----|3 | |
+ | 2 | + | | 2 | | 2 + | | | |
+ | | + | | | | + | | | |
+ | +---+ + | | ----+ | +---+ + | | | |
+ | + | | | | | | + | | ++++++| | |
+ 1 | + | 1 | 1 | | 1 | | 1 + | | | | | |
+ | + | | | | | | + | | | | | |
+ +---+ + +---+ | +---+ +---+ +---+ + | | | | | |
+ | + | | | | + | | | | | |
+ 0 | + | 0 | 0 | | 0 + | | | | | |
+ | + | | | | + | | | | | |
+---+ + +-------+ +---+ + +--- | |+ | |++ | |+
+
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21