解释器模式(Interpreter Pattern)
概念
解释器模式是一种行为设计模式,它为语言定义一个文法,然后为该文法定义一个解释器,使用该解释器来解释语言中的句子。解释器模式定义了语言的文法规则,并建立一个解释器来解释该语言中的句子或表达式。
解释器模式主要用于处理较为简单的语言或表达式,它将一个语言的语句解释成抽象语法树,然后通过遍历这棵语法树来解释执行语句。解释器模式适用于一些特定的领域语言(DSL)解析场景。
基本实现
解释器模式包含以下主要角色:
- AbstractExpression(抽象表达式):声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
- TerminalExpression(终结符表达式):实现文法中的终结符相关的解释操作。
- NonterminalExpression(非终结符表达式):为文法中的非终结符实现解释操作。
- Context(环境类):包含解释器之外的一些全局信息。
- Client(客户端):构建表示文法定义的语言中特定句子的抽象语法树,然后调用解释操作。
下面是解释器模式的基本实现:
javascript
// 抽象表达式
class AbstractExpression {
interpret(context) {
throw new Error('interpret method must be implemented');
}
}
// 终结符表达式 - 数字
class NumberExpression extends AbstractExpression {
constructor(number) {
super();
this.number = number;
}
interpret(context) {
return this.number;
}
}
// 终结符表达式 - 变量
class VariableExpression extends AbstractExpression {
constructor(name) {
super();
this.name = name;
}
interpret(context) {
return context.getVariable(this.name);
}
}
// 非终结符表达式 - 加法
class AddExpression extends AbstractExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
return this.left.interpret(context) + this.right.interpret(context);
}
}
// 非终结符表达式 - 减法
class SubtractExpression extends AbstractExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
return this.left.interpret(context) - this.right.interpret(context);
}
}
// 环境类 - 变量上下文
class Context {
constructor() {
this.variables = new Map();
}
setVariable(name, value) {
this.variables.set(name, value);
}
getVariable(name) {
return this.variables.get(name) || 0;
}
}
// 使用示例
const context = new Context();
context.setVariable('x', 10);
context.setVariable('y', 5);
// 构建表达式: x + y - 3
const expression = new SubtractExpression(
new AddExpression(
new VariableExpression('x'),
new VariableExpression('y')
),
new NumberExpression(3)
);
const result = expression.interpret(context);
console.log(`表达式结果: ${result}`); // 输出: 12实际应用场景
场景1:简单数学表达式计算器
实现一个简单的数学表达式解释器,支持加减乘除运算和括号。
javascript
// 抽象表达式
class Expression {
interpret(context) {
throw new Error('interpret method must be implemented');
}
}
// 数字表达式(终结符)
class NumberExpression extends Expression {
constructor(value) {
super();
this.value = parseFloat(value);
}
interpret(context) {
return this.value;
}
}
// 变量表达式(终结符)
class VariableExpression extends Expression {
constructor(name) {
super();
this.name = name;
}
interpret(context) {
return context.getVariable(this.name) || 0;
}
}
// 加法表达式(非终结符)
class AddExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
return this.left.interpret(context) + this.right.interpret(context);
}
}
// 减法表达式(非终结符)
class SubtractExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
return this.left.interpret(context) - this.right.interpret(context);
}
}
// 乘法表达式(非终结符)
class MultiplyExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
return this.left.interpret(context) * this.right.interpret(context);
}
}
// 除法表达式(非终结符)
class DivideExpression extends Expression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
interpret(context) {
const divisor = this.right.interpret(context);
if (divisor === 0) {
throw new Error('除数不能为零');
}
return this.left.interpret(context) / divisor;
}
}
// 环境类
class CalculatorContext {
constructor() {
this.variables = new Map();
}
setVariable(name, value) {
this.variables.set(name, parseFloat(value));
}
getVariable(name) {
return this.variables.get(name);
}
}
// 表达式解析器
class ExpressionParser {
constructor() {
this.position = 0;
this.tokens = [];
}
// 词法分析 - 将表达式字符串分解为标记
tokenize(expression) {
const tokens = [];
let current = '';
for (let i = 0; i < expression.length; i++) {
const char = expression[i];
if (/\s/.test(char)) {
continue; // 跳过空格
}
if (/[0-9.]/.test(char)) {
current += char;
} else {
if (current) {
tokens.push(current);
current = '';
}
tokens.push(char);
}
}
if (current) {
tokens.push(current);
}
return tokens;
}
// 解析表达式
parse(expression) {
this.tokens = this.tokenize(expression);
this.position = 0;
return this.parseExpression();
}
// 解析表达式(处理加法和减法)
parseExpression() {
let left = this.parseTerm();
while (this.currentToken() === '+' || this.currentToken() === '-') {
const operator = this.consume();
const right = this.parseTerm();
if (operator === '+') {
left = new AddExpression(left, right);
} else {
left = new SubtractExpression(left, right);
}
}
return left;
}
// 解析项(处理乘法和除法)
parseTerm() {
let left = this.parseFactor();
while (this.currentToken() === '*' || this.currentToken() === '/') {
const operator = this.consume();
const right = this.parseFactor();
if (operator === '*') {
left = new MultiplyExpression(left, right);
} else {
left = new DivideExpression(left, right);
}
}
return left;
}
// 解析因子(处理数字、变量和括号)
parseFactor() {
const token = this.currentToken();
if (/[0-9.]+/.test(token)) {
this.consume();
return new NumberExpression(token);
}
if (/[a-zA-Z_][a-zA-Z0-9_]*/.test(token)) {
this.consume();
return new VariableExpression(token);
}
if (token === '(') {
this.consume(); // 消费 '('
const expression = this.parseExpression();
this.consume(); // 消费 ')'
return expression;
}
throw new Error(`Unexpected token: ${token}`);
}
currentToken() {
return this.tokens[this.position];
}
consume() {
return this.tokens[this.position++];
}
}
// 计算器类
class Calculator {
constructor() {
this.context = new CalculatorContext();
this.parser = new ExpressionParser();
}
setVariable(name, value) {
this.context.setVariable(name, value);
}
evaluate(expression) {
try {
const parsedExpression = this.parser.parse(expression);
return parsedExpression.interpret(this.context);
} catch (error) {
console.error(`计算错误: ${error.message}`);
return null;
}
}
}
// 使用示例
const calculator = new Calculator();
// 设置变量
calculator.setVariable('x', 10);
calculator.setVariable('y', 5);
calculator.setVariable('z', 2);
console.log('=== 数学表达式计算 ===');
console.log(`10 + 5 = ${calculator.evaluate('10 + 5')}`);
console.log(`x + y = ${calculator.evaluate('x + y')}`);
console.log(`x * y + z = ${calculator.evaluate('x * y + z')}`);
console.log(`(x + y) * z = ${calculator.evaluate('(x + y) * z')}`);
console.log(`x + y * z = ${calculator.evaluate('x + y * z')}`);
console.log(`x / y = ${calculator.evaluate('x / y')}`);
console.log(`(x + y) / (z + 1) = ${calculator.evaluate('(x + y) / (z + 1)')}`);
try {
console.log(`10 / 0 = ${calculator.evaluate('10 / 0')}`);
} catch (error) {
console.log('除零错误处理正常');
}场景2:SQL查询条件解释器
实现一个简单的SQL WHERE子句解释器,用于解析和执行查询条件。
javascript
// 抽象条件表达式
class ConditionExpression {
evaluate(row) {
throw new Error('evaluate method must be implemented');
}
}
// 字段表达式
class FieldExpression extends ConditionExpression {
constructor(fieldName) {
super();
this.fieldName = fieldName;
}
evaluate(row) {
return row[this.fieldName];
}
}
// 值表达式
class ValueExpression extends ConditionExpression {
constructor(value) {
super();
this.value = value;
}
evaluate(row) {
return this.value;
}
}
// 等于条件表达式
class EqualExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) === this.right.evaluate(row);
}
}
// 不等于条件表达式
class NotEqualExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) !== this.right.evaluate(row);
}
}
// 大于条件表达式
class GreaterThanExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) > this.right.evaluate(row);
}
}
// 小于条件表达式
class LessThanExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) < this.right.evaluate(row);
}
}
// 与条件表达式
class AndExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) && this.right.evaluate(row);
}
}
// 或条件表达式
class OrExpression extends ConditionExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
evaluate(row) {
return this.left.evaluate(row) || this.right.evaluate(row);
}
}
// SQL条件解析器
class SQLConditionParser {
constructor() {
this.tokens = [];
this.position = 0;
}
// 词法分析
tokenize(condition) {
// 简化的词法分析
const regex = /(\w+|'[^']*'|[!=<>]=?|\bAND\b|\bOR\b|[()])/gi;
return condition.match(regex) || [];
}
// 解析条件
parse(condition) {
this.tokens = this.tokenize(condition);
this.position = 0;
return this.parseExpression();
}
// 解析表达式(处理AND和OR)
parseExpression() {
let left = this.parseComparison();
while (this.currentToken() && (this.currentToken().toUpperCase() === 'AND' ||
this.currentToken().toUpperCase() === 'OR')) {
const operator = this.consume().toUpperCase();
const right = this.parseComparison();
if (operator === 'AND') {
left = new AndExpression(left, right);
} else {
left = new OrExpression(left, right);
}
}
return left;
}
// 解析比较条件
parseComparison() {
// 处理括号
if (this.currentToken() === '(') {
this.consume(); // 消费 '('
const expression = this.parseExpression();
this.consume(); // 消费 ')'
return expression;
}
const left = this.parseOperand();
const operator = this.consume();
const right = this.parseOperand();
switch (operator) {
case '=':
return new EqualExpression(left, right);
case '!=':
case '<>':
return new NotEqualExpression(left, right);
case '>':
return new GreaterThanExpression(left, right);
case '<':
return new LessThanExpression(left, right);
case '>=':
return new GreaterThanExpression(left, right);
case '<=':
return new LessThanExpression(left, right);
default:
throw new Error(`Unsupported operator: ${operator}`);
}
}
// 解析操作数
parseOperand() {
const token = this.currentToken();
if (token.startsWith("'") && token.endsWith("'")) {
// 字符串值
this.consume();
return new ValueExpression(token.slice(1, -1));
}
if (/^\d+$/.test(token)) {
// 数字值
this.consume();
return new ValueExpression(parseInt(token));
}
if (/^\d+\.\d+$/.test(token)) {
// 浮点数值
this.consume();
return new ValueExpression(parseFloat(token));
}
// 字段名
this.consume();
return new FieldExpression(token);
}
currentToken() {
return this.tokens[this.position];
}
consume() {
return this.tokens[this.position++];
}
}
// 数据查询器
class DataQuery {
constructor(data) {
this.data = data;
this.parser = new SQLConditionParser();
}
// 执行WHERE查询
where(condition) {
try {
const expression = this.parser.parse(condition);
return this.data.filter(row => expression.evaluate(row));
} catch (error) {
console.error(`查询错误: ${error.message}`);
return [];
}
}
// 显示结果
display(results) {
console.log('查询结果:');
results.forEach((row, index) => {
console.log(`${index + 1}. ${JSON.stringify(row)}`);
});
console.log(`共 ${results.length} 条记录\n`);
}
}
// 使用示例
const data = [
{ id: 1, name: 'Alice', age: 25, department: 'Engineering', salary: 80000 },
{ id: 2, name: 'Bob', age: 30, department: 'Marketing', salary: 70000 },
{ id: 3, name: 'Charlie', age: 35, department: 'Engineering', salary: 90000 },
{ id: 4, name: 'David', age: 28, department: 'Sales', salary: 75000 },
{ id: 5, name: 'Eve', age: 32, department: 'Engineering', salary: 95000 }
];
const query = new DataQuery(data);
console.log('=== SQL条件解释器示例 ===');
console.log('原始数据:');
query.display(data);
console.log('查询条件: age > 30');
const result1 = query.where('age > 30');
query.display(result1);
console.log("查询条件: department = 'Engineering'");
const result2 = query.where("department = 'Engineering'");
query.display(result2);
console.log('查询条件: age > 25 AND salary > 80000');
const result3 = query.where('age > 25 AND salary > 80000');
query.display(result3);
console.log("查询条件: (department = 'Engineering' OR department = 'Marketing') AND age < 35");
const result4 = query.where("(department = 'Engineering' OR department = 'Marketing') AND age < 35");
query.display(result4);
console.log('查询条件: name != "Bob"');
const result5 = query.where('name != "Bob"');
query.display(result5);场景3:正则表达式解释器
实现一个简化的正则表达式解释器,支持基本的匹配操作。
javascript
// 抽象正则表达式
class RegexExpression {
match(text, position) {
throw new Error('match method must be implemented');
}
}
// 字面量表达式
class LiteralExpression extends RegexExpression {
constructor(char) {
super();
this.char = char;
}
match(text, position) {
if (position < text.length && text[position] === this.char) {
return { success: true, nextPosition: position + 1 };
}
return { success: false, nextPosition: position };
}
}
// 任意字符表达式
class AnyCharExpression extends RegexExpression {
match(text, position) {
if (position < text.length) {
return { success: true, nextPosition: position + 1 };
}
return { success: false, nextPosition: position };
}
}
// 连接表达式(序列)
class SequenceExpression extends RegexExpression {
constructor(expressions) {
super();
this.expressions = expressions;
}
match(text, position) {
let currentPos = position;
for (const expr of this.expressions) {
const result = expr.match(text, currentPos);
if (!result.success) {
return { success: false, nextPosition: position };
}
currentPos = result.nextPosition;
}
return { success: true, nextPosition: currentPos };
}
}
// 选择表达式(或)
class ChoiceExpression extends RegexExpression {
constructor(left, right) {
super();
this.left = left;
this.right = right;
}
match(text, position) {
// 尝试左边的表达式
const leftResult = this.left.match(text, position);
if (leftResult.success) {
return leftResult;
}
// 如果左边失败,尝试右边的表达式
return this.right.match(text, position);
}
}
// 星号表达式(零次或多次)
class StarExpression extends RegexExpression {
constructor(expression) {
super();
this.expression = expression;
}
match(text, position) {
let currentPos = position;
// 尝试匹配尽可能多的次数
while (true) {
const result = this.expression.match(text, currentPos);
if (!result.success || result.nextPosition === currentPos) {
// 无法继续匹配或没有前进,停止
break;
}
currentPos = result.nextPosition;
}
return { success: true, nextPosition: currentPos };
}
}
// 加号表达式(一次或多次)
class PlusExpression extends RegexExpression {
constructor(expression) {
super();
this.expression = expression;
}
match(text, position) {
// 至少匹配一次
const firstResult = this.expression.match(text, position);
if (!firstResult.success) {
return { success: false, nextPosition: position };
}
// 然后匹配零次或多次
const starExpr = new StarExpression(this.expression);
const starResult = starExpr.match(text, firstResult.nextPosition);
return { success: true, nextPosition: starResult.nextPosition };
}
}
// 问号表达式(零次或一次)
class QuestionExpression extends RegexExpression {
constructor(expression) {
super();
this.expression = expression;
}
match(text, position) {
// 尝试匹配一次
const result = this.expression.match(text, position);
if (result.success) {
return result;
}
// 匹配失败,但仍然成功(零次匹配)
return { success: true, nextPosition: position };
}
}
// 正则表达式解析器
class RegexParser {
constructor() {
this.pattern = '';
this.position = 0;
}
parse(pattern) {
this.pattern = pattern;
this.position = 0;
return this.parseChoice();
}
parseChoice() {
let left = this.parseSequence();
while (this.currentChar() === '|') {
this.consume(); // 消费 '|'
const right = this.parseSequence();
left = new ChoiceExpression(left, right);
}
return left;
}
parseSequence() {
const expressions = [];
while (this.position < this.pattern.length &&
this.currentChar() !== '|' &&
this.currentChar() !== ')') {
const expr = this.parseFactor();
expressions.push(expr);
}
if (expressions.length === 0) {
// 空表达式匹配任意位置
return new SequenceExpression([]);
}
if (expressions.length === 1) {
return expressions[0];
}
return new SequenceExpression(expressions);
}
parseFactor() {
let expr = this.parseAtom();
while (this.currentChar() === '*' || this.currentChar() === '+' || this.currentChar() === '?') {
const operator = this.consume();
switch (operator) {
case '*':
expr = new StarExpression(expr);
break;
case '+':
expr = new PlusExpression(expr);
break;
case '?':
expr = new QuestionExpression(expr);
break;
}
}
return expr;
}
parseAtom() {
if (this.currentChar() === '(') {
this.consume(); // 消费 '('
const expr = this.parseChoice();
this.consume(); // 消费 ')'
return expr;
}
if (this.currentChar() === '.') {
this.consume(); // 消费 '.'
return new AnyCharExpression();
}
const char = this.consume();
return new LiteralExpression(char);
}
currentChar() {
return this.pattern[this.position];
}
consume() {
return this.pattern[this.position++];
}
}
// 正则表达式引擎
class RegexEngine {
constructor() {
this.parser = new RegexParser();
}
match(pattern, text) {
try {
const expression = this.parser.parse(pattern);
const result = expression.match(text, 0);
return result.success && result.nextPosition === text.length;
} catch (error) {
console.error(`正则表达式错误: ${error.message}`);
return false;
}
}
search(pattern, text) {
try {
const expression = this.parser.parse(pattern);
for (let i = 0; i <= text.length; i++) {
const result = expression.match(text, i);
if (result.success) {
return {
matched: true,
start: i,
end: result.nextPosition,
match: text.substring(i, result.nextPosition)
};
}
}
return { matched: false };
} catch (error) {
console.error(`正则表达式错误: ${error.message}`);
return { matched: false };
}
}
findAll(pattern, text) {
try {
const expression = this.parser.parse(pattern);
const matches = [];
let position = 0;
while (position <= text.length) {
const result = expression.match(text, position);
if (result.success && result.nextPosition > position) {
matches.push({
start: position,
end: result.nextPosition,
match: text.substring(position, result.nextPosition)
});
position = result.nextPosition;
} else {
position++;
}
}
return matches;
} catch (error) {
console.error(`正则表达式错误: ${error.message}`);
return [];
}
}
}
// 使用示例
const regex = new RegexEngine();
console.log('=== 正则表达式解释器示例 ===');
// 基本匹配
console.log(`匹配 "a" 和 "a": ${regex.match('a', 'a')}`);
console.log(`匹配 "a" 和 "b": ${regex.match('a', 'b')}`);
console.log(`匹配 "ab" 和 "ab": ${regex.match('ab', 'ab')}`);
console.log(`匹配 "a.b" 和 "axb": ${regex.match('a.b', 'axb')}`);
console.log(`匹配 "a.b" 和 "ab": ${regex.match('a.b', 'ab')}`);
// 星号匹配
console.log(`匹配 "a*" 和 "": ${regex.match('a*', '')}`);
console.log(`匹配 "a*" 和 "a": ${regex.match('a*', 'a')}`);
console.log(`匹配 "a*" 和 "aa": ${regex.match('a*', 'aa')}`);
console.log(`匹配 "a*" 和 "aaa": ${regex.match('a*', 'aaa')}`);
console.log(`匹配 "a*b" 和 "aab": ${regex.match('a*b', 'aab')}`);
// 加号匹配
console.log(`匹配 "a+" 和 "": ${regex.match('a+', '')}`);
console.log(`匹配 "a+" 和 "a": ${regex.match('a+', 'a')}`);
console.log(`匹配 "a+" 和 "aa": ${regex.match('a+', 'aa')}`);
console.log(`匹配 "a+b" 和 "aab": ${regex.match('a+b', 'aab')}`);
// 问号匹配
console.log(`匹配 "a?" 和 "": ${regex.match('a?', '')}`);
console.log(`匹配 "a?" 和 "a": ${regex.match('a?', 'a')}`);
console.log(`匹配 "a?b" 和 "ab": ${regex.match('a?b', 'ab')}`);
console.log(`匹配 "a?b" 和 "b": ${regex.match('a?b', 'b')}`);
// 选择匹配
console.log(`匹配 "a|b" 和 "a": ${regex.match('a|b', 'a')}`);
console.log(`匹配 "a|b" 和 "b": ${regex.match('a|b', 'b')}`);
console.log(`匹配 "a|b" 和 "c": ${regex.match('a|b', 'c')}`);
console.log(`匹配 "(a|b)c" 和 "ac": ${regex.match('(a|b)c', 'ac')}`);
console.log(`匹配 "(a|b)c" 和 "bc": ${regex.match('(a|b)c', 'bc')}`);
// 搜索功能
console.log('\n=== 搜索功能 ===');
const searchText = 'The quick brown fox jumps over the lazy dog';
console.log(`在 "${searchText}" 中搜索 "fox":`);
console.log(regex.search('fox', searchText));
console.log(`在 "${searchText}" 中搜索 "[a-z]+":`);
console.log(regex.search('[a-z]+', searchText));
console.log(`在 "${searchText}" 中查找所有 "[a-z]+":`);
console.log(regex.findAll('[a-z]+', searchText));
// 实际应用示例
console.log('\n=== 实际应用示例 ===');
const emailPattern = '[a-z]+@[a-z]+\\.[a-z]+';
const emails = [
'user@example.com',
'test@domain.org',
'invalid.email',
'another@test.net'
];
console.log('邮箱验证:');
emails.forEach(email => {
console.log(`${email}: ${regex.match(emailPattern, email)}`);
});关键要点
文法规则定义:需要明确定义语言的文法规则,区分终结符和非终结符。
抽象语法树:将语言句子解析为抽象语法树,通过遍历语法树来解释执行。
递归解释:解释器通常使用递归方式解释表达式,每个节点负责解释自己的部分。
上下文管理:通过环境类管理解释过程中的全局信息和状态。
与其他模式的关系
- 与组合模式结合:解释器模式中抽象语法树的结构与组合模式相似。
- 与访问者模式结合:可以使用访问者模式来遍历和操作抽象语法树。
- 与策略模式区别:解释器模式专注于语言解释,而策略模式专注于算法封装。
优缺点
优点:
- 易于扩展:可以很容易地增加新的表达式类型,符合开闭原则。
- 易于实现:对于简单的文法,实现起来相对容易。
- 灵活性:可以动态地构建和解释表达式。
缺点:
- 性能问题:对于复杂的文法,解释器的性能可能较差。
- 类膨胀:每条文法规则都需要一个类,可能导致类的数量急剧增加。
- 调试困难:由于使用了大量的对象和递归调用,调试可能比较困难。
解释器模式适用于相对简单的语言或表达式解析场景,如配置文件解析、简单查询语言、模板引擎等。对于复杂的语言,通常会使用专业的编译器生成工具。