文章

解释器模式 (Interpreter Pattern) 深度解析

解释器模式 (Interpreter Pattern) 深度解析

📜 解释器模式 (Interpreter Pattern) 深度解析

1. 模式动机与定义

1.1. 模式动机:固定文法的解释执行

在软件开发中,我们经常需要处理一些具有固定文法规则的“语言”,例如正则表达式、SQL 查询、简单的数学表达式,或者领域特定语言 (DSL)。

  • 核心问题:如何为这种语言定义一种表示方式,并使其能够解释该语言中的句子?
  • 解决方案:解释器模式将语言的每个规则表示为一个类,并组合这些类来构建一个抽象语法树 (Abstract Syntax Tree, AST)。该解释器遍历 AST 来解释语言中的句子。

何时使用:如果一种特定类型的问题(例如表达式求值、简单命令解析)发生的频率足够高,那么就值得将该问题的实例表述为一个简单语言中的句子,并构建解释器来解决。

1.2. 模式定义

解释器模式 (Interpreter Pattern)

给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

解释器模式是一种对象行为型模式,它提供了评估语言的语法或表达式的方式。

2. 模式结构与角色

解释器模式的核心在于定义表达式的层次结构,通常使用组合模式来构建抽象语法树。

角色名称职责描述对应到布尔表达式实例
AbstractExpression (抽象表达式)声明一个抽象的解释操作 (interpret),所有具体的表达式类都实现该接口。Expression 接口
TerminalExpression (终结符表达式)实现与文法中终结符相关的解释操作。它是语法树的叶节点。TerminalExpression (代表 “John”, “Married”)
NonterminalExpression (非终结符表达式)实现与文法中非终结符相关的解释操作。它通常包含(组合)一个或多个 AbstractExpression 实例。它是语法树的枝节点。OrExpression, AndExpression
Context (环境类)包含解释器之外的一些全局信息。在表达式求值时,用于存储或传递信息(如变量值、上下文状态)。客户端传递的 String context

2.1. 模式分析核心

  • 构建 AST:解释器模式的关键是利用终结符和非终结符表达式构建一个抽象语法树,这通常是通过递归实现的。
  • 文法对应:文法中的每一个规则(无论是终结符还是非终结符)都对应于一个表达式类。
  • 递归解释:解释器通过递归调用语法树中节点的 interpret() 方法来解释整个句子。

3. 代码深度解析(布尔逻辑表达式)

我们以布尔逻辑表达式的判断为例,规则是 (Robert OR John)(Julie AND Married)

3.1. Java 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.Map;

// --- 1. 抽象表达式 (AbstractExpression) ---
public interface Expression {
    // Context 通常是一个字符串或一个包含全局信息的对象
    public boolean interpret(String context);
}

// --- 2. 终结符表达式 (TerminalExpression) ---
// 检查 Context 中是否包含特定数据
public class TerminalExpression implements Expression {
    private String data;
    
    public TerminalExpression(String data) {
        this.data = data;
    }
    
    @Override
    public boolean interpret(String context) {
        // 终结符:检查上下文是否包含该终结符
        if (context.contains(data)) {
            return true;
        }
        return false;
    }
}

// --- 3. 非终结符表达式 A: 或逻辑 ---
public class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;
    
    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }
    
    @Override
    public boolean interpret(String context) {
        // 递归解释:对子表达式求值并执行逻辑操作
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

// --- 4. 非终结符表达式 B: 与逻辑 ---
public class AndExpression implements Expression {
    private Expression expr1;
    private Expression expr2;
    
    public AndExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }
    
    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) && expr2.interpret(context);
    }
}

// --- 5. 客户端/解释器创建者 (Client) ---
public class InterpreterPatternDemo {
    
    // 构造规则:(Robert OR John)
    public static Expression getMaleExpression() {
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");
        return new OrExpression(robert, john); // 组合成 AST
    }
    
    // 构造规则:(Julie AND Married)
    public static Expression getMarriedWomanExpression() {
        Expression julie = new TerminalExpression("Julie");
        Expression married = new TerminalExpression("Married");
        return new AndExpression(julie, married); // 组合成 AST
    }
    
    public static void main(String[] args) {
        Expression isMale = getMaleExpression();
        Expression isMarriedWoman = getMarriedWomanExpression();
        
        // 解释句子 1
        System.out.println("John is male? " + isMale.interpret("John"));
        
        // 解释句子 2 (Context = "Married Julie")
        System.out.println("Julie is a married woman? " 
            + isMarriedWoman.interpret("Married Julie"));
        
        // 解释句子 3
        System.out.println("Julie is male? " + isMale.interpret("Julie"));
    }
}

3.2. Python 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
from abc import ABC, abstractmethod

# --- 1. 抽象表达式 (AbstractExpression) ---
class Expression(ABC):
    @abstractmethod
    def interpret(self, context: dict) -> bool:
        pass

# --- 2. 终结符表达式 (TerminalExpression) ---
# 检查变量名是否存在于 Context 中
class VariableExpression(Expression):
    def __init__(self, name: str):
        self._name = name

    def interpret(self, context: dict) -> bool:
        # 终结符:直接从上下文获取值
        return context.get(self._name, False)

# --- 3. 非终结符表达式 A: 逻辑非 ---
class NotExpression(Expression):
    def __init__(self, expr: Expression):
        self._expr = expr

    def interpret(self, context: dict) -> bool:
        # 递归解释:取反
        return not self._expr.interpret(context)

# --- 4. 非终结符表达式 B: 逻辑与 ---
class AndExpression(Expression):
    def __init__(self, expr1: Expression, expr2: Expression):
        self._expr1 = expr1
        self._expr2 = expr2

    def interpret(self, context: dict) -> bool:
        # 递归解释:执行 AND 逻辑
        return self._expr1.interpret(context) and self._expr2.interpret(context)

# --- 5. 客户端/解释器创建者 (Client) ---
if __name__ == "__main__":
    
    # 构建 AST: (A AND (NOT B))
    a = VariableExpression("A")
    b = VariableExpression("B")
    
    not_b = NotExpression(b)
    final_expression = AndExpression(a, not_b)
    
    # Context 1: A=True, B=False -> (True AND True) = True
    context1 = {"A": True, "B": False, "C": True}
    result1 = final_expression.interpret(context1)
    print(f"Context 1: {context1} -> Result: {result1}")
    
    # Context 2: A=True, B=True -> (True AND False) = False
    context2 = {"A": True, "B": True, "C": False}
    result2 = final_expression.interpret(context2)
    print(f"Context 2: {context2} -> Result: {result2}")
    
    # Context 3: A=False, B=False -> (False AND True) = False
    context3 = {"A": False, "B": False, "C": False}
    result3 = final_expression.interpret(context3)
    print(f"Context 3: {context3} -> Result: {result3}")

4. 模式优点与缺点

4.1. 优点

  1. 易于实现简单文法:对于固定的、简单的文法,解释器模式提供了一种清晰的表示方式。
  2. 可扩展性好:增加新的解释表达式的方式(新的非终结符规则)相对容易,只需增加对应的 NonterminalExpression 类,符合“开闭原则”。
  3. 文法易于改变和管理:由于每个文法规则都对应一个类,文法的修改和维护被局部化。

4.2. 缺点

  1. 类膨胀:对于复杂的文法,文法规则数量会急剧增加,导致类数量过多,难以维护。
  2. 场景局限:模式的可利用场景比较少,仅适用于那些可以表示为语言并需要解释执行的固定、简单语法。
  3. 递归调用复杂:解释器模式采用递归调用方法,可能增加调试难度。

5. 适用环境

  1. 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
  2. 一个简单语法需要解释的场景,例如简单的数学表达式、布尔表达式、正则表达式或领域特定语言 (DSL)。
  3. 一些重复出现的问题可以用一种简单的语言来进行表达。
  4. 当文法相对简单稳定,且易于实现时。
本文由作者按照 CC BY 4.0 进行授权