当前位置: 首页 > news >正文

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

文章目录

  • 前言
  • 一、命令模式
  • 二、命令模式示例


前言

GOF设计模式分三大类:

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

一、命令模式

命令模式(Command Pattern)

  • 定义:
    • 将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化
    • 对请求排队或者记录请求日志
    • 支持可撤销的操作
  • 解决问题:如何将请求的发送者和请求的接收者完全解耦?
  • 使用场景:
    • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
    • 系统需要在不同的时间指定请求、将请求排队和执行请求。
    • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
    • 系统需要将一组操作组合在一起形成宏命令。
  • 组成:
    • Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
    • ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法。它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
    • Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
    • Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。
  • 补充说明:
    • 在软件开发中也存在很多与开关和电器类似的请求发送者和接收者对象。发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。
    • 在命令模式中,发送者与接收者之间引入了新的命令对象,将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法。
    • 命令模式的核心在于引入了命令类。请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。
    • 通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。
    • 命令模式的本质是对请求进行封装。一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。
    • 命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。
    • 命令模式是一种使用频率非常高的设计模式。
  • 优点:
    • 降低系统的耦合度。新的命令可以很容易地加入系统中。可以比较容易地设计一个命令队列或宏命令(组合命令)。为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。
  • 缺点:
    • 可能会导致某些系统有过多的具体命令类。

在这里插入图片描述

二、命令模式示例

使用命令模式来设计“自定义功能键”模块,将功能键和相应功能自由绑定

  • FunctionButton充当请求调用者,Command充当抽象命令类,MinimizeCommand和HelpCommand充当具体命令类,WindowHandler和HelpHandler充当请求接收者。
  • FBSettingWindow是“功能键设置”界面类
### 命令模式
"""请求发送者"""class FunctionButton:def __init__(self, name: str):self.name = name  # 功能键名称self.cmd: Cmd = None  # 抽象命令对象的引用def on_click(self):# 发送请求print("点击功能键:", end="")self.cmd.execute()"""请求接收者"""class WindowHandler:# 窗口处理def minimize(self):print("将窗口最小化到托盘!")class HelpHandler:# 帮助文档处理def display(self):print("显示帮助文档!")"""抽象命令类"""class Cmd:def execute(self):raise NotImplementedError"""具体命令类"""class MinimizeCmd(Cmd):# 最小化命令def __init__(self):self.wh_obj = WindowHandler()def execute(self):# 命令执行:调用请求接收者的业务方法self.wh_obj.minimize()class HelpCmd(Cmd):# 帮助命令def __init__(self):self.hh_obj = HelpHandler()  # 请求接收者的引用def execute(self):# 命令执行:调用请求接收者的业务方法self.hh_obj.display()"""功能键设置界面"""class FBSettingWindow:def __init__(self, title: str):self.title = title  # 窗口标题self.function_buttons: list[FunctionButton] = []  # 存储所有功能键def add_function_button(self, fb: FunctionButton):if fb not in self.function_buttons:self.function_buttons.append(fb)def remove_function_button(self, fb: FunctionButton):if fb in self.function_buttons:self.function_buttons.remove(fb)def display(self):# 显示窗口及功能键print(f"显示窗口:{self.title}")print("显示功能键:")for i in self.function_buttons:print(i.name)print("#" * 10)
  • 为了提高系统的灵活性和可扩展性,这里将具体命令类的类名存储在配置文件command_conf.json中,并通过工具类XMLUtil来读取配置文件并反射生成对象。JsonUtil类的代码如下:
# 模块 utils.py
from pathlib import Path
import jsonclass JsonUtil:@staticmethoddef get_value(key: str, conf_file="config.json"):"""读取配置文件,返回配置文件中的配置"""path = Path(conf_file)contents = path.read_text(encoding="utf-8")conf = json.loads(contents)return conf.get(key, None)
  • 配置文件command_conf.json中存储了具体命令类的类名,代码如下:
{"class_name_1": "HelpCmd","class_name_2": "MinimizeCmd"
}
  • 客户端代码
"""客户端代码"""from command import FBSettingWindow, FunctionButton, Cmd
from utils import JsonUtil
import command# 通过读取配置文件和反射生成具体命令对象
class_name_1 = JsonUtil.get_value("class_name_1", "command_conf.json")
class_name_2 = JsonUtil.get_value("class_name_2", "command_conf.json")
if class_name_1 is None or class_name_2 is None:raise ValueError
cmd1: Cmd = getattr(command, class_name_1)()
cmd2: Cmd = getattr(command, class_name_2)()
# 创建功能键并绑定功能
fb1 = FunctionButton("功能键1")
fb2 = FunctionButton("功能键2")
fb1.cmd = cmd1
fb2.cmd = cmd2
# 调用功能键的业务方法
fb1.on_click()
fb2.on_click()
# 显示窗口及功能键
fbsw = FBSettingWindow("功能键设置")
fbsw.add_function_button(fb1)
fbsw.add_function_button(fb2)
fbsw.display()
  • 输出结果
点击功能键:显示帮助文档!
点击功能键:将窗口最小化到托盘!
显示窗口:功能键设置
显示功能键:
功能键1
功能键2
##########
  • 如果需要修改功能键的功能,例如某个功能键可以实现“自动截屏”,只需要对应增加一个新的具体命令类。在该命令类与屏幕处理者(ScreenHandler)之间创建一个关联关系,然后将该具体命令类的对象通过配置文件注入某个功能键即可,原有代码无须修改,符合开闭原则。

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

相关文章:

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

文章目录 前言一、命令模式二、命令模式示例 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对象之间的组合&…...

C语言之循环结构:直到型循环

C语言 循环结构 直到型循环的实现 特点:先执行,后判断,不管条件是否满足,至少执行一次。典型代表:do…while,goto(已淘汰,不推荐使用) do…while 语法: d…...

细说STM32F407单片机RTC的备份寄存器原理及使用方法

目录 一、备份寄存器的功能 二、示例功能 三、项目设置 1、晶振、DEBUG、CodeGenerator、USART6 2、RTC 3、NVIC 4、GPIO 及KEYLED 四、软件设计 1、main.h 2、main.c 3、rtc.c 4、keyled.c、keyled.h 五、运行调试 本实例旨在介绍备份寄存器的作用。本实例继续使…...

MATLAB计算反映热需求和能源消耗的度数日指标(HDD+CDD)(全代码)

目录 度数日(Degree Days, DD)概述计算公式MATLAB计算代码调用函数1:计算单站点的 CDD参考度数日(Degree Days, DD)概述 度数日(Degree Days, DD)是用于衡量建筑、城市和地区的热需求和能源消耗模式的指标。它分为两部分: 加热度日(Heating Degree Days, HDD):当室…...

J6 X8B/X3C切换HDR各帧图像

1、OV手册上的切换命令 寄存器为Ox5074 各帧切换: 2、地平线control tool实现切换命令 默认HDR模式出图: HCG出图: LCG出图 SPD出图 VS出图...

09-轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 方法一:使用额外数组 function rotate(nums: number[], k: number): void {const n nums.length;k k % n; // 处理 k 大于数组长度的情况const newNums new A…...

用vue3写一个好看的wiki前端页面

以下是一个使用 Vue 3 Element Plus 实现的 Wiki 风格前端页面示例&#xff0c;包含现代设计、响应式布局和常用功能&#xff1a; <template><div class"wiki-container"><!-- 头部导航 --><el-header class"wiki-header"><d…...

瑞芯微烧写工具

文章目录 前言一、安装驱动二、安装烧写工具1.直接解压压缩包2. 如何使用 三、MASKROM 裸机必备四、LOADER 烧写&#xff0c;前提是搞过第三步没问题五、Update.img包的烧录六、linux下烧写总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要…...

说下JVM中一次完整的GC流程?

大家好&#xff0c;我是锋哥。今天分享关于【说下JVM中一次完整的GC流程?】面试题。希望对大家有帮助&#xff1b; 说下JVM中一次完整的GC流程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 JVM中的一次完整的垃圾回收&#xff08;GC&#xff09;流程可以概括为…...

Open FPV VTX开源之OSD使用分类

Open FPV VTX开源之OSD使用分类 1. 源由2. 硬件2.1 【天空端】SigmaStar2.2 【天空端】Raspberry Pi2.3 【地面端】 3. 软件3.1 天空端软件3.2 地面端软件 4. 分类4.1 嵌入式OSD分类A1-嵌入式OSD&#xff1a;SigmaStar Android分类A2-嵌入式OSD&#xff1a;SigmaStar Hi3536分…...

智慧农业-虫害及生长预测

有害生物防控系统是一个综合性的管理体系&#xff0c;旨在预防和控制对人类生活、生产甚至生存产生危害的生物。这些生物可能包括昆虫、动物、植物、微生物乃至病毒等。 一、系统构成 1、监测预警系统&#xff1a;利用智能传感器、无人机、遥感技术等手段&#xff0c;实时监测…...

Python 识别图片和扫描PDF中的文字

目录 工具与设置 Python 识别图片中的文字 Python 识别图片中的文字及其坐标位置 Python 识别扫描PDF中的文字 注意事项 在处理扫描的PDF和图片时&#xff0c;文字信息往往无法直接编辑、搜索或复制&#xff0c;这给信息提取和分析带来了诸多不便。手动录入信息不仅耗时费…...

C语言如何知道当前系统中的编译器数据类型的大小是多少?

在 C 语言中&#xff0c;你可以使用sizeof运算符来确定当前系统中编译器数据类型的大小&#xff0c;该运算符返回一个size_t类型的值&#xff0c;表示所操作对象或数据类型占用的字节数。下面为你详细介绍使用方法&#xff1a; 1. 基本数据类型大小的获取 基本数据类型如char…...

gitlab Webhook 配置jenkins时“触发远程构建 (例如,使用脚本)”报错

报错信息&#xff1a; <html> <head> <meta http-equiv"Content-Type" content"text/html;charsetISO-8859-1"/> <title>Error 403 No valid crumb was included in the request</title> </head> <body><h2…...

Mysql中使用sql语句生成雪花算法Id

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…...

/etc/profile vs ~/.bashrc:如何正确使用?

在 Linux 或 WSL 环境中&#xff0c;我们经常需要配置环境变量、命令别名、路径等信息。然而&#xff0c;许多人在配置时会纠结&#xff1a;到底应该放在 /etc/profile 还是 ~/.bashrc&#xff1f;本文将全面解析它们的区别&#xff0c;并帮助你做出正确的选择。 1. 什么是 /et…...

SpringBoot实战:高效获取视频资源

文章目录 前言技术实现SpringBoot项目构建产品选取配置数据采集 号外号外 前言 在短视频行业高速发展的背景下&#xff0c;海量内容数据日益增长&#xff0c;每天都有新的视频、评论、点赞、分享等数据涌现。如何高效、精准地获取并处理这些庞大的数据&#xff0c;已成为各大平…...

Flutter_学习记录_数据更新的学习

Flutter 如果界面上有数据更新时&#xff0c;目前学习到的有3种&#xff1a; 第一种&#xff1a; 直接用 StatefulWidget组件&#xff0c;然后当数据更新时&#xff0c;调用setState的方法更新数据&#xff0c;页面上的数据会直接更新&#xff1b;第二种&#xff1a; 用 State…...

c++ 多线程知识汇总

一、std::thread std::thread 是 C11 引入的标准库中的线程类&#xff0c;用于创建和管理线程 1. 带参数的构造函数 template <class F, class... Args> std::thread::thread(F&& f, Args&&... args);F&& f&#xff1a;线程要执行的函数&…...

day09_实时类标签/指标

文章目录 day09_实时类标签/指标一、日志数据实时采集2、Flume简介2.3 项目日志数据采集Flume配置2.3.1 涉及的Flume组件和参数2.3.2 Nginx日志采集2.3.3 用户行为日志采集 二、Nginx日志数据统计1、日志格式说明2、数据ETL2.1 日志抽取2.1.1 正则表达式2.1.2 基于Spark实现Ngi…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

Linux安全加固:从攻防视角构建系统免疫

Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...