主页 > 游戏开发  > 

设计模式Python版命令模式(下)

设计模式Python版命令模式(下)

文章目录 前言一、命令队列的实现二、撤销操作的实现三、请求日志四、宏命令


前言

GOF设计模式分三大类:

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

如果还没有阅读第一部分,可以点击这里进行回顾:《设计模式Python版 命令模式(上)》。现在,继续第二部分。

一、命令队列的实现

命令队列

有时需要将多个请求排队。当一个请求发送者发送一个请求时,不止一个请求接收者产生响应,这些请求接收者将逐个执行业务方法,完成对请求的处理。此时,可以通过命令队列来实现。命令队列的实现方法有多种形式,其中最常用、灵活性最好的一种方式是增加一个CommandQueue类。CommandQueue类负责存储多个命令对象,而不同的命令对象可以对应不同的请求接收者。 """命令队列""" class CmdQueue: def __init__(self): self.cmds: list[Cmd] = [] # 存储命令队列 def add_cmd(self, cmd: Cmd): if cmd not in self.cmds: self.cmds.append(cmd) def remove_cmd(self, cmd: Cmd): if cmd in self.cmds: self.cmds.remove(cmd) def execute(self): # 调用每一个命令对象的execute()方法 for i in self.cmds: i.execute() """请求发送者""" class Invoker: def __init__(self, cmd_queue: CmdQueue): self.cmd_queue = cmd_queue # CmdQueue的引用 def call(self): self.cmd_queue.execute() 命令队列与批处理有点类似。批处理,顾名思义,可以对一组对象(命令)进行批量处理,当一个发送者发送请求后,将有一系列接收者对请求做出响应。命令队列可以用于设计批处理应用程序。 二、撤销操作的实现

在命令模式中,可以通过调用一个命令对象的execute()方法来实现对请求的处理。如果需要撤销(Undo)请求,可通过在命令类中增加一个逆向操作来实现。

示例:一个简易计算器,该计算器可以实现简单的数学运算,还可以对运算实施撤销操作。计算器界面类CalculatorForm充当请求发送者,实现数据求和功能的加法类Adder充当请求接收者,界面类可间接调用加法类中的add()方法实现加法运算,并且提供可撤销加法运算的undo()方法。由于没有保存命令对象的历史状态,只能实现一步撤销操作。 """请求发送者""" class CalculatorForm: def __init__(self): self.cmd: AbstractCmd = None def compute(self, value: int): i = self.cmd.execute(value) print(f"执行运算,运算结果为:{i}") def undo(self): i = self.cmd.undo() print(f"执行撤销,运算结果为:{i}") """请求接收者""" class Adder: def __init__(self): self.num = 0 # 初始值为0 def add(self, value: int) -> int: # 每次将传入的值与num作加法运算,再将结果返回 self.num += value return self.num """抽象命令类""" class AbstractCmd: # 执行方法 def execute(self, value: int) -> int: raise NotImplementedError # 撤销方法 def undo(self) -> int: raise NotImplementedError """具体命令类""" class AddCmd(AbstractCmd): def __init__(self): self.adder = Adder() def execute(self, value): # 调用加法类的加法操作 self.value = value return self.adder.add(value) def undo(self): # 通过加一个相反数来实现加法的逆向操作 return self.adder.add(-self.value) 客户端代码 form = CalculatorForm() cmd: AbstractCmd = AddCmd() form.cmd = cmd form pute(10) form pute(5) form pute(10) form.undo() 输出结果 执行运算,运算结果为:10 执行运算,运算结果为:15 执行运算,运算结果为:25 执行撤销,运算结果为:15 三、请求日志

请求日志就是将请求的历史记录保存下来,通常以日志文件(Log File)的形式永久存储在计算机中。

很多系统都提供了日志文件,例如Windows日志文件、Oracle日志文件等。请求日志文件常用功能如下: 一旦系统发生故障,日志文件可以为系统提供一种恢复机制。请求日志也可以用于实现批处理。可以将命令队列中的所有命令对象都存储在一个日志文件中。每执行一个命令则从日志文件中删除一个对应的命令对象,防止因为断电或者系统重启等原因造成请求丢失。而且可以避免重新发送全部请求时造成某些命令的重复执行。 在实现请求日志时,可以将命令对象通过序列化写到日志文件中

示例:将对网站配置文件的操作请求记录在日志文件中,如果网站重新部署,只需要执行保存在日志文件中的命令对象即可修改配置文件。

from pathlib import Path import pickle """请求发送者""" class ConfigSettingWindow: # 配置文件设置窗口 def __init__(self): self.cmds: list[Cmd] = [] # 存储每一次操作时的命令对象 self.cmd: Cmd = None def call(self, args): # 执行配置文件修改命令,同时将命令对象添加到命令集合中 self.cmd.execute(args) self.cmds.append(self.cmd) def save(self): # 将命令集合写入日志文件 FileUtil.write_cmds(self.cmds) def recover(self): # 从日志文件中提取命令集合,并遍历调用每一个命令对象的execute()方法来实现配置文件的重新设置 cmds = FileUtil.read_cmds() for i in cmds: i.execute(i.args) """请求接收者""" class ConfigOperator: # 配置文件操作 def insert(self, args: str): print(f"增加新节点:{args}") def modify(self, args: str): print(f"修改节点:{args}") def delete(self, args: str): print(f"删除节点:{args}") """抽象命令类""" class Cmd: def __init__(self, name: str): self.name = name self.config_operator: ConfigOperator = None # 请求接收者对象的引用 self.args = None def execute(self, args): raise NotImplementedError """具体命令类""" class InsertCmd(Cmd): # 增加 def __init__(self, name): super().__init__(name) def execute(self, args): self.args = args self.config_operator.insert(args) class ModifyCmd(Cmd): # 修改 def __init__(self, name): super().__init__(name) def execute(self, args): self.args = args self.config_operator.modify(args) class DeleteCmd(Cmd): # 删除 def __init__(self, name): super().__init__(name) def execute(self, args): self.args = args self.config_operator.delete(args) """工具类:文件操作""" class FileUtil: @staticmethod def write_cmds(cmds: list[Cmd]): # 将命令集合写入日志文件 try: file = Path("command_config.log") contents = pickle.dumps(cmds) file.write_bytes(contents) except Exception as e: print("命令保存失败!") print(e) @staticmethod def read_cmds() -> list[Cmd]: # 从日志文件中提取命令集合 try: file = Path("command_config.log") contents = file.read_bytes() cmds = pickle.loads(contents) return cmds except Exception as e: print("命令读取失败!") print(e) 客户端代码 if __name__ == "__main__": csw = ConfigSettingWindow() # 定义请求发送者 co = ConfigOperator() # 定义请求接收者 # 4次对配置文件进行更必 cmd = InsertCmd("增加") cmd.config_operator = co csw.cmd = cmd csw.call("网站首页") cmd = InsertCmd("增加") cmd.config_operator = co csw.cmd = cmd csw.call("端口号") cmd = ModifyCmd("修改") cmd.config_operator = co csw.cmd = cmd csw.call("网站首页") cmd = ModifyCmd("修改") cmd.config_operator = co csw.cmd = cmd csw.call("端口号") print("#" * 20) print("保存配置") csw.save() print("#" * 20) print("恢复配置") csw.recover() 输出结果 增加新节点:网站首页 增加新节点:端口号 修改节点:网站首页 修改节点:端口号 #################### 保存配置 #################### 恢复配置 增加新节点:网站首页 增加新节点:端口号 修改节点:网站首页 修改节点:端口号 四、宏命令

宏命令

宏命令(Macro Command)又称为组合命令,它是组合模式和命令模式联用的产物。宏命令是一个具体命令类,它拥有一个集合属性,在该集合中包含了对其他命令对象的引用。当调用宏命令的execute()方法时,将递归调用它所包含的每个成员命令的execute()方法。一个宏命令的成员可以是简单命令,还可以继续是宏命令。执行一个宏命令将触发多个具体命令的执行,从而实现对命令的批处理。宏命令结构图如下


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

标签:

设计模式Python版命令模式(下)由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“设计模式Python版命令模式(下)