设计模式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 = Nonedef 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  # 初始值为0def add(self, value: int) -> int:# 每次将传入的值与num作加法运算,再将结果返回self.num += valuereturn 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 = valuereturn self.adder.add(value)def undo(self):# 通过加一个相反数来实现加法的逆向操作return self.adder.add(-self.value)
  • 客户端代码
form = CalculatorForm()
cmd: AbstractCmd = AddCmd()
form.cmd = cmd
form.compute(10)
form.compute(5)
form.compute(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 = Nonedef 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 = nameself.config_operator: ConfigOperator = None  # 请求接收者对象的引用self.args = Nonedef execute(self, args):raise NotImplementedError"""具体命令类"""class InsertCmd(Cmd):# 增加def __init__(self, name):super().__init__(name)def execute(self, args):self.args = argsself.config_operator.insert(args)class ModifyCmd(Cmd):# 修改def __init__(self, name):super().__init__(name)def execute(self, args):self.args = argsself.config_operator.modify(args)class DeleteCmd(Cmd):# 删除def __init__(self, name):super().__init__(name)def execute(self, args):self.args = argsself.config_operator.delete(args)"""工具类:文件操作"""class FileUtil:@staticmethoddef 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)@staticmethoddef read_cmds() -> list[Cmd]:# 从日志文件中提取命令集合try:file = Path("command_config.log")contents = file.read_bytes()cmds = pickle.loads(contents)return cmdsexcept Exception as e:print("命令读取失败!")print(e)
  • 客户端代码
if __name__ == "__main__":csw = ConfigSettingWindow()  # 定义请求发送者co = ConfigOperator()  # 定义请求接收者# 4次对配置文件进行更必cmd = InsertCmd("增加")cmd.config_operator = cocsw.cmd = cmdcsw.call("网站首页")cmd = InsertCmd("增加")cmd.config_operator = cocsw.cmd = cmdcsw.call("端口号")cmd = ModifyCmd("修改")cmd.config_operator = cocsw.cmd = cmdcsw.call("网站首页")cmd = ModifyCmd("修改")cmd.config_operator = cocsw.cmd = cmdcsw.call("端口号")print("#" * 20)print("保存配置")csw.save()print("#" * 20)print("恢复配置")csw.recover()
  • 输出结果
增加新节点:网站首页
增加新节点:端口号
修改节点:网站首页
修改节点:端口号
####################
保存配置
####################
恢复配置
增加新节点:网站首页
增加新节点:端口号
修改节点:网站首页
修改节点:端口号

四、宏命令

宏命令

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

在这里插入图片描述


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/18448.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux:进程概念详解

​ 进程概念详解 一、进程的基本概念 进程在书本上的定义是:计算机中正在运行的程序实例。仅此描述可能让很多人感到困惑。 我们磁盘上存储着.exe文件,启动文件时,文件会从磁盘加载到内存,由CPU对文件的数据和代码进行运算。但…

04性能监控与调优篇(D1_学习前言)

目录 一、引言 二、基本介绍 三、JVM基础 1. java堆 2. 垃圾回收 3. STW 四、调优层次 五、调优指标 六、JVM调优原则 1. 优先原则 2. 堆设置 3. 垃圾回收器设置 1> GC 发展阶段 2> G1的适用场景 3> 其他收集器适⽤场景 4. 年轻代设置 5. 年⽼代设置 …

系统思考—慢就是快

“所有成长,都是一个缓慢渗透的过程,回头看,才发现自己已经走了很远。” —— 余秋雨 这让我想起一个最近做的项目。和一家公司合作,他们的管理模式一直陷入困境,员工积极性低,领导层的决策效率也不高。刚…

String常量池(2)

大家好,今天我们继续学习String常量池,昨天我们已经做了一个介绍,相信大家✓String常量池有了一定了解,那么就来看看它的应用。 字符串常量地(String Table). 字常量她在IVM中是StringTable类,实际是一个固定大小的 HashTable(一…

LabVIEW显微镜成像偏差校准

在高精度显微镜成像中,用户常常需要通过点击图像的不同位置,让电机驱动探针移动到指定点进行观察。然而,在实际操作中,经常会遇到一个问题:当点击位于图像中心附近的点时,探针能够相对准确地定位&#xff1…

Typora“使用”教程

文章目录 零、Typora简介一、下载并安装Typora二、修改License文件三、每次启动第一个Typora时,总弹出Activate窗口四、去除软件左下角未Activate提示五、参考文章 零、Typora简介 Typora 是一款由 Abner Lee 开发的轻量级 Markdown 编辑器,与其他 Mark…

【scikit-multiflow】使用 scikit-multiflow 的流数据生成器生成概念漂移数据流

说在前面 scikit-multiflow 是一个专注于多流学习(multi-stream learning)的Python库,它为数据流挖掘和在线学习提供了丰富的工具集。这个库的设计灵感来源于著名的scikit-learn,旨在为研究人员和从业者提供一个易于使用且功能强…

计算机视觉-局部特征

一、局部特征 1.1全景拼接 先用RANSAC估计出变换,就可以拼接两张图片 ①提取特征 ②匹配特征 ③拼接图像 1.2 点的特征 怎么找到对应点?(才能做点对应关系RANSAC) :特征检测 我们希望找到的点具有的特征有什么特…

matlab下载安装图文教程

【matlab介绍】 MATLAB是一款由美国MathWorks公司开发的专业计算软件,主要应用于数值计算、可视化程序设计、交互式程序设计等高科技计算环境。以下是关于MATLAB的简要介绍: MATLAB是MATrix LABoratory(矩阵实验室)的缩写&#…

Whisper+T5-translate实现python实时语音翻译

1.首先下载模型,加载模型 import torch import numpy as np import webrtcvad import pyaudio import queue import threading from datetime import datetime from faster_whisper import WhisperModel from transformers import AutoTokenizer, AutoModelForSeq2…

Python微博动态爬虫

本文是刘金路的《语言数据获取与分析基础》第十章的扩展,详细解释了如何利用Python进行微博爬虫,爬虫内容包括微博指定帖子的一级评论、评论时间、用户名、id、地区、点赞数。 整个过程十分明了,就是用户利用代码模拟Ajax请求,发…

爬虫实战:利用代理ip爬取推特网站数据

引言 亮数据-网络IP代理及全网数据一站式服务商屡获殊荣的代理网络、强大的数据挖掘工具和现成可用的数据集。亮数据:网络数据平台领航者https://www.bright.cn/?promoRESIYEAR50/?utm_sourcebrand&utm_campaignbrnd-mkt_cn_csdn_yingjie202502 在跨境电商、社…

2.认识标签和去标签|下载boost库|建立项目结构

下载Boost库 Boost C Libraries 选择右边的Documentation 选择最新的1.87.0版本 可以在首页的这里下载最新版本 建立项目结构 新建目录boost_searcher mkdir boost_searcher移动到boost_searcher目录 cd boost_searcher下载rz命令 yum install lrzsz导入boost文件&…

Transformer 模型介绍(三)——自注意力机制 Self-Attention

Transformer 模型由 Vaswani 等人于2017年提出,主要应用于序列到序列的任务,最初应用于机器翻译。其核心思想是通过自注意力机制捕捉序列中的长期依赖关系,从而有效地进行任务建模 在著名的论文《Attention Is All You Need》中,…

《AI大模型开发笔记》Open-R1:对 DeepSeek-R1 的完全开源再现(翻译)

Open-R1:对 DeepSeek-R1 的完全开源再现(翻译) 原文链接:https://huggingface.co/blog/open-r1 什么是 DeepSeek-R1? 如果你曾经为一道艰难的数学题苦思冥想,那么你就知道花更多时间、仔细推理是多么有用…

Java虚拟机面试题:JVM调优

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…

每日Attention学习23——KAN-Block

模块出处 [SPL 25] [link] [code] KAN See In the Dark 模块名称 Kolmogorov-Arnold Network Block (KAN-Block) 模块作用 用于vision的KAN结构 模块结构 模块代码 import torch import torch.nn as nn import torch.nn.functional as F import mathclass Swish(nn.Module)…

Centos安装php-8.0.24.tar

查看系统环境 cat /etc/redhat-release 预先安装必要的依赖 yum install -y \ wget \ gcc \ gcc-c \ autoconf \ automake \ libtool \ make \ libxml2 \ libxml2-devel \ openssl \ openssl-devel \ sqlite-devel yum update 1、下载解压 cd /data/ wget https:/…

百度千帆平台对接DeepSeek官方文档

目录 第一步:注册账号,开通千帆服务 第二步:创建应用,获取调用秘钥 第三步:调用模型,开启AI对话 方式一:通过API直接调用 方式二:使用SDK快速调用 方式三:在千帆大模…

linux-shell脚本

shell的编码语法 shell脚本的第一行内容是: #!/bin/bash,这句话相当于是一个导包语句,将shell的执行环境引入进去了。 shell中变量的命名要求: 只能使用数字、字母和下划线,且不能以数字开头 变量赋值是通过"&q…