设计模式---解释器模式

6 阅读3分钟

定义

解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一种语言的语法表示,并提供一个解释器来解释这些语言中的句子。这个模式主要用于处理符号、表达式、语言等复杂的解析和计算任务,特别是当这些任务可以用一种语法规则进行描述时。

结构

  • 抽象表达式(Abstract Expression) :定义了所有解释器所需的接口。通常包括一个 interpret 方法,用于解释或计算一个表达式。

  • 终结符表达式(Terminal Expression) :实现了抽象表达式接口,代表文法中的终结符。它通常用来实现具体的语法元素,例如操作符或常量。在解释器模式中,终结符是文法中最基本的元素,它们无法再被进一步分解为更小的部分。终结符是语法规则中的最小构建块,比如在数学表达式解释器中,如 3, 5, 10 等,它们是具体的数值,无法进一步分解。

  • 非终结符表达式(Non-terminal Expression) :同样实现了抽象表达式接口,代表文法中的非终结符。它通常用于组合终结符或其他非终结符来形成更复杂的表达式非终结符如数学表达式解释器中的加法 +、减法 -,这些操作符需要与其他表达式组合以形成完整的计算。例如,在 3 + 5 中,加法操作符需要两个数字来进行计算。

  • 上下文(Context) :在解释过程中提供必要的环境或数据。它可以包含有关表达式的状态信息,用于解释或计算(可选)。

代码示例

#include <iostream>

// 抽象表达式类
class Expression
{
public:
	virtual ~Expression() = default;
	virtual int interpret() const = 0;
};


// 终结符表达式:数字
class Number : public Expression
{
private : 
	int value;

public:
	Number(int value) : value(value) {}
	int interpret() const override
	{
		return value;
	}
};


// 非终结符表达式:加法
class Add : public Expression
{
private:
	std::shared_ptr<Expression> left;
	std::shared_ptr<Expression> right;

public:
	Add(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
		:left(left), right(right) {}

	int interpret() const override
	{
		return left->interpret() + right->interpret();
	}
};


// 非终结符表达式:减法
class Subtract : public Expression
{
private:
	std::shared_ptr<Expression> left;
	std::shared_ptr<Expression> right;

public:
	Subtract(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
		:left(left), right(right) {}

	int interpret() const override
	{
		return left->interpret() - right->interpret();
	}
};


int main()
{
	// 手动构建表达式树
	// 8 + 3 - 5 + 2 - 7

	auto number8 = std::make_shared<Number>(8);
	auto number3 = std::make_shared<Number>(3);
	auto number5 = std::make_shared<Number>(5);
	auto number2 = std::make_shared<Number>(2);
	auto number7 = std::make_shared<Number>(7);

	// (8 + 3)
	auto add1 = std::make_shared<Add>(number8, number3);

	// (8 + 3) - 5
	auto sub1 = std::make_shared<Subtract>(add1, number5);

	// ((8 + 3) - 5) + 2
	auto add2 = std::make_shared<Add>(sub1, number2);

	// (((8 + 3) - 5) + 2) - 7
	auto result = std::make_shared<Subtract>(add2, number7);

	// 输出计算结果
	std::cout << "Result: " << result->interpret() << std::endl; // 输出结果: 1

	system("pause");
	return 0;
}

上述示例直接构建了表达式树,通过逐步构造和连接表达式对象来计算复杂的数学表达式。它适用于简单的情况,但对于更复杂的表达式解析,使用解析函数来自动生成表达式树通常更为方便:

// 解析和构建表达式
std::shared_ptr<Expression> parse(const std::string& expression) {
	size_t pos = 0;
	std::shared_ptr<Expression> left;

	while (pos < expression.size()) {
		if (std::isdigit(expression[pos])) {
			int value = 0;
			while (pos < expression.size() && std::isdigit(expression[pos])) {
				value = value * 10 + (expression[pos] - '0');
				++pos;
			}
			left = std::make_shared<Number>(value);
		}
		else if (expression[pos] == '+') {
			++pos;
			auto right = parse(expression.substr(pos));
			left = std::make_shared<Add>(left, right);
			break;
		}
		else if (expression[pos] == '-') {
			++pos;
			auto right = parse(expression.substr(pos));
			left = std::make_shared<Subtract>(left, right);
			break;
		}
		else {
			++pos;
		}
	}

	return left;
}

总结

解释器模式通过将复杂的解析任务分解为简单的、易于管理的组件,允许你定义、解释和执行特定语言或规则。它适用于以下场景:

  • 需要解析和执行复杂语法或表达式的任务。
  • 需要动态创建和解析自定义语言、配置文件或数据格式。
  • 需要处理一系列相似操作的任务,通过定义统一的语法来简化这些操作。