Python 如何实现 Command(命令)模式?什么是 Command(命令)设计模式?

什么是命令设计模式?

命令模式(Command Design Pattern)是一种行为设计模式,它将请求封装成一个对象,从而允许参数化客户端对象,排队请求,或者对请求进行操作。命令模式支持撤销操作,并通过将操作参数化来实现操作的延迟执行。

在这里插入图片描述

主要角色:

  1. 命令(Command): 声明执行操作的接口。通常包含 execute() 方法。

  2. 具体命令(ConcreteCommand): 实现命令接口,具体定义要执行的操作。

  3. 调用者/请求者(Invoker): 要求命令执行请求的对象。

  4. 接收者(Receiver): 知道如何执行一个请求的对象。

  5. 客户端(Client): 创建具体命令对象,并设置其接收者。

工作流程:

  1. 客户端创建一个具体命令对象,并设置其接收者。

  2. 客户端将命令对象传递给调用者/请求者。

  3. 调用者调用命令的 execute() 方法。

  4. 具体命令对象调用接收者的方法执行实际操作。

优点:

  • 松散耦合: 请求者和接收者解耦,请求者无需知道接收者的具体实现。

  • 可扩展性: 可以轻松添加新的命令和接收者,无需修改现有代码。

  • 支持撤销和恢复: 可以轻松实现命令的撤销和恢复操作。

  • 命令队列: 可以将命令存储在队列中,实现命令的排队执行。

Python实现命令模式示例代码(一):

以下是一个简单的命令模式的示例,假设有一个遥控器(Invoker)和灯(Receiver):

# 命令接口
class Command:
    def execute(self):
        pass

# 具体命令
class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

# 接收者
class Light:
    def turn_on(self):
        print("Light is ON")

# 调用者/请求者
class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

# 客户端
light = Light()
light_on = LightOnCommand(light)

remote = RemoteControl()
remote.set_command(light_on)
remote.press_button()

在这个例子中,LightOnCommand 是一个具体的命令,它将操作(turn_on)封装成一个命令对象。RemoteControl 是调用者,它接收一个命令并在按下按钮时执行该命令。

Python实现命令模式实例代码(二)

在 Python 中,你可以通过定义接口、具体命令类、接收者类以及调用者类来实现命令模式。以下是一个简单的示例:

from abc import ABC, abstractmethod

# 命令接口
class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

# 具体命令
class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_off()

# 接收者
class Light:
    def turn_on(self):
        print("Light is ON")

    def turn_off(self):
        print("Light is OFF")

# 调用者/请求者
class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

# 客户端
light = Light()
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

remote = RemoteControl()

# 设置并执行打开灯的命令
remote.set_command(light_on)
remote.press_button()

# 设置并执行关闭灯的命令
remote.set_command(light_off)
remote.press_button()

在这个例子中,Command 是命令的抽象接口,LightOnCommandLightOffCommand 是具体的命令类,分别用于打开和关闭灯。Light 是接收者类,它包含了实际执行操作的方法。RemoteControl 是调用者类,它接收一个命令并在按下按钮时执行该命令。

这个例子演示了命令模式的核心思想:将请求封装成对象,以便参数化客户端对象、排队请求、或者记录请求日志,并支持可撤销的操作。


使用Command命令模式有什么要注意的?

在使用 Command 命令模式时,有一些注意事项和最佳实践,以确保模式的有效实现和易维护的代码:

  1. 接口设计: 定义清晰简洁的命令接口,确保所有具体命令都实现了这个接口。这有助于保持一致性,使得新的命令可以轻松地添加到系统中。

  2. 单一职责原则: 每个具体命令应该只负责一个具体的操作。这有助于保持代码的可读性和可维护性。

  3. 撤销操作: 如果系统需要支持命令的撤销操作,确保命令对象能够保存执行前的状态,并提供一个撤销操作的接口。这需要在设计时考虑。

  4. 命令参数化: 如果命令需要接收参数,确保参数化得当。这可以通过在命令的构造函数中传递参数,或者通过定义命令的执行方法来传递参数。

  5. 调用者与接收者的关系: 确保调用者和接收者之间的关系清晰。调用者不需要知道接收者的具体实现,而是通过命令对象与接收者交互。

  6. 异常处理: 在执行命令时,考虑可能发生的异常情况。确保能够适当地处理异常,提供有意义的错误信息。

  7. 命令的生命周期: 考虑命令对象的生命周期。命令是否需要一直存在,还是可以在执行后被销毁?这有助于优化资源管理。

  8. 命令队列: 如果系统需要支持命令队列,确保命令队列的管理和执行是线程安全的。

  9. 测试: 对命令模式进行适当的单元测试。确保每个具体命令以及整个命令模式的行为都符合预期。

  10. 可扩展性: 考虑系统的可扩展性。命令模式支持方便地添加新的命令,确保设计能够容易地适应变化。

遵循这些最佳实践可以帮助确保 Command 命令模式在系统中的有效应用,并提高代码的可读性和可维护性。


感谢阅读本文!希望通过这篇介绍,让你对命令模式有了更深入的理解,并能在实际的软件设计中灵活运用这一设计模式。

如果您对软件设计模式、编程技术以及其他相关主题感兴趣,欢迎关注、收藏、点赞本文,还有更多精彩的文章等着你。Thanks♪(・ω・)ノ

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

傅里叶分析(2)

在《傅里叶分析(1)》中,讲述了连续信号的傅里叶分析方法,本文讲述离散信号的傅里叶分析方法。 虽然电、声、光、机械振动等信号在物理上是连续函数,但在实际工程中,其通常为离散信号,即若干离散…

设计模式之模版方法(TemplateMethod)

模版方法 钩子函数 回调函数 在父类里面有一个模版方法,在这个方法里面调用了op1,op2,op3… 在子类里面如果想要改变父类的op1和op2 只需要重写op1和op2,那么这个重写之后的方法,可以在父类里面直接调用的到 例子: J…

ctfshow sql171-179

mysql 先打开我们本地的mysql,可以看到这些数据库 information_schema information_schema 库: 是信息数据库,其中保存着关于MySQL服务器所维护的所有其他数据库的信息比如数据库名,数据库表, SCHEMATA表: 提供了当前MySQL实例…

Linux下MSSQL (SQL Server)数据库无法启动故障处理

有同事反馈一套CentOS7下的mssql server2017无法启动需要我帮忙看看,启动报错情况如下 检查日志并没有更新日志信息 乍一看mssql-server服务有问题,检查mssql也确实没有进程 既然服务有问题,那么我们用一种方式直接手工后台启动mssql引擎来…

22.构造一个关于员工信息的结构体数组,存储十个员工的信息

结构体问题。构造一个关于员工信息的结构体数组,存储十个员工的信息,包括员工工号,员工工资,员工所得税,员工实发工资。要求工号和工资由键盘输入,并计算出员工所得税(所得税工资*0.2&#xff0…

C语言--1,5,10人民币若干,现在需要18元,一共有多少种?

今天小编给大家分享一下穷举法的一道典型例题 一.题目描述 1,5,10人民币若干,现在需要18元,一共有多少种? 二.思路分析 总共有18块钱,设1元有x张,5元有y张,10元有z张,则有表达式:x5y10z18,穷举法最重要的…

java网络编程之UDP协议

文章目录 UDP简介一发一收客户端:服务端: 多发多收实现多开客户端:服务端 UDP简介 UDP(User Datagram Protocol) DatagramSocket 用于创建客户端、服务端DatagramSocket() :创建客户端的Socket对象,系统随…

Java 算法篇-深入了解单链表的反转(实现:用 5 种方式来具体实现)

🔥博客主页: 小扳_-CSDN博客 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 单链表的反转说明 2.0 单链表的创建 3.0 实现单链表反转的五种方法 3.1 实现单链表反转 - 循环复制(迭代法) 3.2 实现单链表反转 - 头插法 3…

什么是浏览器指纹?指纹浏览器如何避免浏览器指纹的追踪识别?

在做独立站跨境电商的过程中,海外社交媒体平台已成为我们必不可少的交易渠道。但是,由于各大平台对账号管理极其严格,对账户进行严密监控也成为了常态。这当然与浏览器指纹识别有关,今天龙哥就给大家科普一下什么是浏览器指纹&…

Autosar模块介绍:Memory_4(EA-EE抽象)

上一篇 | 返回主目录 | 下一篇 Autosar模块介绍:Memory_4(EA-EE抽象 1 基本术语解释2 Ea组成结构图3 Ea基本操作3.1 通用操作3.2 作业的进程(通用需求)3.3 读操作过程3.4 写操作过程3.5 擦除过程3.6 比较过程 4 Ea常用操作时序4.1 初始化4.2…

如何搞垮一个测试团队?

要想彻底搞垮一个测试团队并非易事,需要多角色通力配合、多方联动、综合施策,才能达到目的。 本文从实践经验出发,为大家总结了搞垮测试团队的18项措施,或许可以给大家带来一些启发。 — 1 — QA QA作为质量管理者,…

轻量封装WebGPU渲染系统示例<29>- 深度模糊DepthBlur(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/DepthBlur.ts 当前示例运行效果: 此示例基于此渲染系统实现,当前示例TypeScript源码如下: const blurRTTTex0 { diffuse: { uuid: "rtt0", …

【vue】虚拟dom的原理是什么?手写实现虚拟dom !

1.虚拟dom的原理 虚拟 DOM 是对 DOM 的抽象,本质上就是用 JavaScript 对象来描述 DOM 结构。Vue.js 中关于虚拟 DOM 的实现主要进行了以下几个步骤: 1.生成虚拟 DOM: Vue.js 使用 render 函数来依据模板代码生成虚拟 DOM。在这个过程中&a…

【Java 进阶篇】JQuery DOM操作:Class属性的舞蹈魔法

在前端的世界中,JQuery如同一位舞者,通过灵活的舞步为我们展示了操纵HTML元素的艺术。而在这场舞蹈的精彩演出中,Class属性的操作是一项极富魅力的技艺。在本篇博客中,我们将深入研究JQuery DOM操作中的Class属性操作,…

gradle 使用记录

gradle 使用记录 下载与设置android studio 配置 参考 IDEA如何配置 Gradle 及 Gradle 安装过程(详细版) 设置Gradle国内镜像并配置本地仓库地址 下载与设置 腾讯镜像下载 比如gradle-8.4-bin.zip 新建环境变量 GRADLE_HOME 为 D:\java\gradle &#…

【深圳1024开发者城市聚会】主理人视角的聚会现场,一起来看看有啥不一样的东西

【深圳1024开发者城市聚会】主理人视角的聚会现场,一起来看看有啥不一样的东西 今年的1024,我们在深圳,玩点不一样的… 文章目录 1 活动背景2 活动宣传3 活动准备4 活动现场布置会场会场引导签到深圳站视频展播前半程议题分分享简单茶歇后半场…

【HttpRunnerManager】搭建接口自动化测试平台实战

一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和配置、mysql 安装和配置 2. python: django 配置、uwsgi 配置 二、我搭建的环境 1. Centos7 (配置 rabbitmq、mysql 、Supervisord) 2. python 3.6.8 (配置 django、uwsgi&am…

力扣双周赛 -- 117(容斥原理专场)

class Solution { public:long long c2(long long n){return n > 1? n * (n - 1) / 2 : 0;}long long distributeCandies(int n, int limit) {return c2(n 2) - 3 * c2(n - limit 1) 3 * c2(n - 2 * limit) - c2(n - 3 * limit - 1);} };

死锁(JAVA)

死锁在多线程代码中是非常严重的BUG,一旦代码中出现死锁就会导致线程卡死。 当单个线程连续两次对同一个对象进行加锁操作时,如果该锁是不可重入锁就会发生死锁(线程卡死) 两个线程两把锁,如果出现这种情况也是会发生…

基于Python+Django的寻人失物失物招领系统

运行环境 开发语言:Python python框架:django 软件版本:python3.7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:PyCharm/vscode 前端框架:vue.js 项目介绍 寻人失物失物招领系统交流平台的主要使用…