设计模式Python版 解释器模式

文章目录


前言

GOF设计模式分三大类:

  • 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
  • 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
  • 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

一、解释器模式

解释器模式(Interpreter Pattern)

  • 定义:定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的"语言"是指使用规定格式和语法的代码。

  • 解决问题:如何自定义一个简单的语言?

  • 使用场景:

    • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
    • 一些重复出现的问题可以用一种简单的语言来进行表达。
    • 一个语言的文法较为简单。执行效率不是关键问题。
  • 组成:

    • AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
    • TerminalExpression(终结符表达式):是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常,在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
    • NonterminalExpression(非终结符表达式):也是抽象表达式的子类,它实现了文法中非终结符的解释操作。由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
    • Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。
  • 补充说明:

    • 解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器。
    • 在解释器模式中每一条文法规则都将对应一个类
    • 解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。
    • 表达式可分为终结符表达式和非终结符表达式
  • 优点:

    • 易于改变和扩展文法。每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。实现文法较为容易。增加新的解释表达式较为方便。
  • 缺点:

    • 对于复杂文法难以维护。执行效率较低。

二、解释器示例

使用解释器模式实现对机器人控制指令的处理

  • 假设机器人控制程序中包含一些简单的英文控制指令,每个指令对应一个表达式(expression),该表达式可以是简单表达式,也可以是复合表达式。
  • 每个简单表达式由移动方向(direction)、移动方式(action)和移动距离(distance)三部分组成,其中移动方向包括上(up)、下(down)、左(left)、右(right);移动方式包括移动(move)和快速移动(run);移动距离为一个正整数。两个表达式之间可以通过与(and)连接,形成复合(composite)表达式。
  • 5条文法规则
  • 5条文法规则,分别提供5个类来实现。其中,终结符表达式direction、action和distance对应DirectionNode类、ActionNode类和DistanceNode类,非终结符表达式expression和composite对应SentenceNode类和AndNode类。
  • AbstractNode充当抽象表达式角色,DirectionNode、ActionNode和DistanceNode充当终结符表达式角色,AndNode和SentenceNode充当非终结符表达式角色。
  • 本示例只是将机器人控制指令的输出结果进行模拟(即将英文指令翻译为中文指令),实际情况是调用不同的控制程序进行机器人的控制
sh 复制代码
### 解释器模式
"""抽象表达式"""


class AbstractNode:
    def interpret(self) -> str:
        raise NotImplementedError


"""终结符表达式"""


class DirectionNode(AbstractNode):
    def __init__(self, direction: str):
        self.direction = direction

    def interpret(self):
        # 动作方向的解释操作
        kw = {"up": "向上", "down": "向下", "left": "向左", "right": "向右"}
        return kw.get(self.direction, "无效指令")


class ActionNode(AbstractNode):
    def __init__(self, action: str):
        self.action = action

    def interpret(self):
        # 动作移动方式的解释操作
        kw = {"move": "移动", "run": "快速移动"}
        return kw.get(self.action, "无效指令")


class DistanceNode(AbstractNode):
    def __init__(self, distance: str):
        self.distance = distance

    def interpret(self):
        # 距离表达式的解释操作
        return self.distance


"""非终结符达式"""


class AndNode(AbstractNode):
    def __init__(self, left: AbstractNode, right: AbstractNode):
        self.left = left  # and的左表达式
        self.right = right  # and的右表达式

    def interpret(self):
        # and表达式解释操作
        return self.left.interpret() + " 再 " + self.right.interpret()


class SentenceNode(AbstractNode):
    def __init__(
        self, direction: AbstractNode, action: AbstractNode, distance: AbstractNode
    ):
        self.direction = direction
        self.action = action
        self.distance = distance

    def interpret(self):
        # 句子解释操作
        return (
            self.direction.interpret()
            + self.action.interpret()
            + self.distance.interpret()
        )


"""指令处理:工具类"""


class InstructionHandler:
    def __init__(self):
        self.node: AbstractNode = None

    def handle(self, instruction: str):
        stack: list[AbstractNode] = []  # 用于存储抽象语法树,模拟栈的特性
        words = instruction.split(" ")  # 以空格分隔指认字符串
        i = 0
        while i < len(words):
            # 采用栈的特性来处理指令
            if words[i] == "and":
                # 如果遇到and,则将其后的3个单词作为3个终结符表达式连成一个简单句子,作为and的右表达式;
                # 而将从栈顶弹出的表达式作为and的左表达式;最后将新的and表达式入栈。
                left = stack.pop()
                direction = DirectionNode(words[i + 1])
                action = ActionNode(words[i + 2])
                distance = DistanceNode(words[i + 3])
                right = SentenceNode(direction, action, distance)
                stack.append(AndNode(left, right))
                i += 3  # and后面的3个单词已使用
            else:
                # 如果是从头开始进行解释,则将前3个单词组成一个简单句子并将其入栈
                direction = DirectionNode(words[i])
                action = ActionNode(words[i + 1])
                distance = DistanceNode(words[i + 2])
                left = SentenceNode(direction, action, distance)
                stack.append(left)
                i += 2  # 后面的2个单词已使用
            i += 1
        self.node = stack.pop()

    def output(self) -> str:
        return self.node.interpret()
  • 客户端代码
python 复制代码
if __name__ == "__main__":
    instruction = "up move 5 and down run 10 and left move 5"
    handler = InstructionHandler()
    handler.handle(instruction)
    print(handler.output())
  • 输出结果
sh 复制代码
向上移动5 再 向下快速移动10 再 向左移动5

三、解释器模式环境类

解释器模式环境类Context

  • 环境类Context用于存储解释器之外的一些全局信息。它通常作为参数被传递到所有表达式的解释方法interpret()中,可以在Context对象中存储和访问表达式解释器的状态,向表达式解释器提供一些全局的、公共的数据。
  • 可以在Context中增加一些所有表达式解释器都共有的功能,减轻解释器的职责。

您正在阅读的是《设计模式Python版》专栏!关注不迷路~

相关推荐
思则变1 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
GodKeyNet1 小时前
设计模式-模板模式
设计模式·模板模式
漫谈网络1 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find3 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
博观而约取4 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
缘来是庄5 小时前
设计模式之建造者模式
java·设计模式·建造者模式
精灵vector5 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习5 小时前
Python入门Day2
开发语言·python
Vertira5 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉5 小时前
Python之 sorted() 函数的基本语法
python