解释器模式

98 阅读3分钟

1. 简介

解释器模式(Interpreter Pattern)是一种设计模式,属于行为型模式。它用于解决一些特定类型的问题,其中一种常见的情况是需要解释和执行特定语言或规则的语法。解释器模式通过定义一种语言文法并提供一个解释器来解释该语言中的表达式,从而实现对语言的解释和执行。

2. 模式结构

classDiagram
    class Client {
        +main()
    }
    
    class AbstractExpression {
        <<interface>>
        +interpret()
    }
    
    class TerminalExpression {
        -value: Any
        +interpret()
    }
    
    class NonTerminalExpression {
        -value: TerminalExpression
        +interpret()
    }
    
    class Context {
        -stack: List[AbstractExpression]
        +interpret(expression: Any)
    }
        
    Client ..> Context
    Context o-- AbstractExpression
    AbstractExpression <|.. TerminalExpression
    AbstractExpression <|.. NonTerminalExpression

解释器模式通常包含以下几个角色:

  1. 抽象表达式(Abstract Expression) :定义解释器的接口,包含一个 interpret() 方法,用于解释语言中的表达式。
  2. 终结符表达式(Terminal Expression) :实现抽象表达式接口的类,用于表示语言中的终结符,例如变量或常量等。
  3. 非终结符表达式(Non-terminal Expression) :实现抽象表达式接口的类,用于表示语言中的非终结符,即由多个终结符组成的复杂表达式。
  4. 上下文环境(Context) :包含需要解释和执行的语言表达式,并提供解释器的解释方法。
  5. 客户端(Client) :创建并配置上下文环境,然后调用解释器来解释和执行语言表达式。

3. 使用场景

解释器模式适用于以下情况:

  • 当有一种语言或规则需要解释和执行,并且该语言的表达式可以用类似树状结构的方式表示时。
  • 当需要频繁修改和扩展语言的语法规则时,解释器模式可以更加灵活地支持这种变化。

需要注意的是,解释器模式的缺点是对于复杂的语法规则或表达式,可能会产生大量的类和对象,从而导致系统复杂性增加。因此,需要权衡使用解释器模式的利弊,并根据具体的情况来选择是否使用。

4. 练习:【设计模式专题之解释器模式】22-数学表达式

""" 
【设计模式专题之解释器模式】22-数学表达式
时间限制:1.000S  空间限制:256MB
题目描述
小明正在设计一个计算器,用于解释用户输入的简单数学表达式,每个表达式都是由整数、加法操作符+、乘法操作符组成的,表达式中的元素之间用空格分隔,请你使用解释器模式帮他实现这个系统。
输入描述
每行包含一个数学表达式,表达式中包含整数、加法操作符(+)和乘法操作符(*)。 表达式中的元素之间用空格分隔。
输出描述
对于每个输入的数学表达式,每行输出一个整数,表示对应表达式的计算结果。
输入示例
2 + 3
5 * 2
3 + 4 * 2
输出示例
5
10
11
"""
from abc import ABC, abstractmethod
from typing import List, Optional


class AbstractExpression(ABC):
    @abstractmethod
    def interpret(self):
        raise NotImplemented
        
        
class NumberExpression(AbstractExpression):
    def __init__(self, value: int):
        self.value = value
        
    def interpret(self):
        return self.value
        

class AddExpression(AbstractExpression):
    def __init__(self, x: Optional[NumberExpression] = None, y: Optional[NumberExpression] = None):
        self.value = "+"
        self.x = x 
        self.y = y
        
    def interpret(self):
        return self.x.interpret() + self.y.interpret()
        
        
class MultiplyExpression(AbstractExpression):
    def __init__(self, x: Optional[NumberExpression] = None, y: Optional[NumberExpression] = None):
        self.value = "*"
        self.x = x 
        self.y = y
        
    def interpret(self):
        return self.x.interpret() * self.y.interpret()
        
        
class Context:
    def __init__(self):
        self.stackNumber: List[NumberExpression] = []
        self.stackOperation: List[AbstractExpression] = []
        self.priority = {"+": 1, "*": 2}
        
    def interpret(self, expression: str):
        """ 将中缀表达式解释为表达式二叉树 """
        s = expression
        n = len(s)
        i = 0
        while i < n:
            if s[i] == " ":
                pass
            elif s[i].isnumeric():
                j = i 
                while i + 1 < n and s[i + 1].isnumeric():
                    i += 1 
                num = int(s[j:i + 1])
                self.stackNumber.append(NumberExpression(num))
            else:
                assert expression[i] in ["+", "*"]
                while self.stackOperation and self.priority[self.stackOperation[-1].value] >= self.priority[s[i]]:
                    x = self.stackNumber.pop()
                    y = self.stackNumber.pop()
                    opt = self.stackOperation.pop()
                    opt.x, opt.y = x, y
                    self.stackNumber.append(opt)
                if s[i] == "+":
                    self.stackOperation.append(AddExpression())
                if s[i] == "*":
                    self.stackOperation.append(MultiplyExpression())
            i += 1
        while self.stackOperation:
            x = self.stackNumber.pop()
            y = self.stackNumber.pop()
            opt = self.stackOperation.pop()
            opt.x, opt.y = x, y
            self.stackNumber.append(opt)
        resultExp = self.stackNumber.pop()
        return resultExp
        

def client():
    ctx = Context()
    while True:
        try:
            expression = input()
        except EOFError:
            break
        else:
            resultExp = ctx.parse(expression)
            print(resultExp.interpret())
            
            
if __name__ == "__main__":
    client()

5. 参考文章

  1. 1597. 根据中缀表达式构造二叉表达式树
  2. 双栈法统一解决基本计算器三种类型
  3. 卡码网设计模式-解释器模式