设计模式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版》专栏!关注不迷路~

相关推荐
小怪兽会微笑13 分钟前
PyTorch Tensor 形状变化操作详解
人工智能·pytorch·python
测试199843 分钟前
接口测试工具:Postman
自动化测试·软件测试·python·测试工具·职场和发展·接口测试·postman
秋窗71 小时前
Mac下Python版本管理,适用于pyenv不起作用的情况
开发语言·python·macos
付聪12101 小时前
装饰器模式
设计模式
扣丁梦想家1 小时前
设计模式教程:外观模式(Facade Pattern)
设计模式·外观模式
強云1 小时前
23种设计模式 - 装饰器模式
c++·设计模式·装饰器模式
強云1 小时前
23种设计模式 - 外观模式
设计模式·外观模式
代码轨迹1 小时前
青龙面板运行selenium启动Chrome报错
chrome·python·selenium
咩咩大主教2 小时前
人工智能神经网络
人工智能·python·深度学习·神经网络·机器学习·bp神经网络