文章目录
前言
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版》专栏!关注不迷路~