Python設計模式:命令模式

1. 什么是命令模式?

命令模式是一種行為設計模式,它將請求封裝為一個對象,從而使您能夠使用不同的請求、隊列或日志請求,以及支持可撤銷操作。
命令模式的核心思想是將請求的發送者與請求的接收者解耦,使得兩者之間的交互更加靈活。

1.1 命令模式的組成部分

命令模式通常包含以下幾個組成部分,每個部分都有其特定的角色和功能。下面將詳細介紹每個組成部分,并提供相應的代碼示例。

1.1.1 命令接口(Command Interface)

命令接口定義了一個執行操作的接口,通常包含一個 execute 方法。所有具體命令類都需要實現這個接口。

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

1.1.2 具體命令類(Concrete Command)

具體命令類實現命令接口,定義與接收者之間的綁定關系,并調用接收者的相應操作。每個具體命令類都對應一個特定的操作。

# 接收者
class Light:def turn_on(self):print("The light is ON")def turn_off(self):print("The light is OFF")# 具體命令類
class LightOnCommand(Command):def __init__(self, light):self.light = lightdef execute(self):self.light.turn_on()class LightOffCommand(Command):def __init__(self, light):self.light = lightdef execute(self):self.light.turn_off()

1.1.3 接收者(Receiver)

接收者是具體的業務邏輯類,包含實際執行操作的方法。命令對象會調用接收者的方法來完成請求。

class Light:def turn_on(self):print("The light is ON")def turn_off(self):print("The light is OFF")

1.1.4 調用者(Invoker)

調用者持有命令對象并在適當的時候調用命令的 execute 方法。調用者不需要知道命令的具體實現,只需調用命令接口。

示例代碼
class RemoteControl:def __init__(self):self.command = Nonedef set_command(self, command):self.command = commanddef press_button(self):if self.command:self.command.execute()

1.1.5 客戶端(Client)

客戶端負責創建具體命令對象并設置接收者。客戶端代碼通常會將命令對象傳遞給調用者。

if __name__ == "__main__":# 創建接收者light = Light()# 創建具體命令light_on = LightOnCommand(light)light_off = LightOffCommand(light)# 創建調用者remote = RemoteControl()# 開燈remote.set_command(light_on)remote.press_button()  # 輸出: The light is ON# 關燈remote.set_command(light_off)remote.press_button()  # 輸出: The light is OFF
  1. 命令接口:定義了一個命令接口 Command,包含一個 execute 方法,所有具體命令類都需要實現這個方法。

  2. 具體命令類LightOnCommandLightOffCommand 實現了命令接口,分別用于打開和關閉燈。它們持有一個 Light 對象的引用,并在 execute 方法中調用相應的接收者方法。

  3. 接收者Light 類是接收者,包含實際執行操作的方法 turn_onturn_off

  4. 調用者RemoteControl 類持有命令對象,并在適當的時候調用命令的 execute 方法。它提供了 set_command 方法來設置命令對象。

  5. 客戶端代碼:在客戶端代碼中,創建接收者、具體命令和調用者,并通過調用者執行命令。客戶端代碼不需要知道命令的具體實現,只需使用命令接口。

1.2 命令模式的優點

1.2.1 解耦

說明:命令模式通過將請求的發送者與接收者解耦,使得發送者不需要知道接收者的具體實現。這種解耦使得系統更加靈活,便于維護和擴展。

1. 靈活性:發送者可以在不修改代碼的情況下替換接收者。
# 接收者
class Light:def turn_on(self):print("The light is ON")def turn_off(self):print("The light is OFF")# 具體命令類
class LightOnCommand(Command):def __init__(self, light):self.light = lightdef execute(self):self.light.turn_on()# 新的接收者
class Fan:def turn_on(self):print("The fan is ON")def turn_off(self):print("The fan is OFF")# 客戶端代碼
light = Light()
fan = Fan()light_on_command = LightOnCommand(light)
light_on_command.execute()  # 輸出: The light is ON# 替換接收者
fan_on_command = LightOnCommand(fan)  # 這里可以直接替換為 Fan
fan_on_command.execute()  # 輸出: The fan is ON
2. 可維護性:修改接收者的實現不會影響發送者。
# 修改接收者的實現
class Light:def turn_on(self):print("The light is now ON")# 客戶端代碼
light = Light()
light_on_command = LightOnCommand(light)
light_on_command.execute()  # 輸出: The light is now ON
3. 可擴展性:輕松添加新命令而不修改現有代碼。
# 新的具體命令類
class LightOffCommand(Command):def __init__(self, light):self.light = lightdef execute(self):self.light.turn_off()# 客戶端代碼
light_off_command = LightOffCommand(light)
light_off_command.execute()  # 輸出: The light is OFF
4. 支持多種請求:可以處理不同類型的請求。
# 另一個具體命令類
class FanOnCommand(Command):def __init__(self, fan):self.fan = fandef execute(self):self.fan.turn_on()# 客戶端代碼
fan_on_command = FanOnCommand(fan)
fan_on_command.execute()  # 輸出: The fan is ON

如果不采用解耦的設計,可能會面臨以下風險:

1. 緊耦合:請求的發送者和接收者之間的緊耦合關系。
# 緊耦合示例
class RemoteControl:def __init__(self):self.light = Light()  # 直接依賴于具體的接收者def turn_on_light(self):self.light.turn_on()# 客戶端代碼
remote = RemoteControl()
remote.turn_on_light()  # 輸出: The light is ON
2. 難以擴展:添加新功能需要修改現有代碼。
# 添加新功能需要修改現有代碼
class RemoteControl:def __init__(self):self.light = Light()self.fan = Fan()  # 需要修改代碼以添加新功能def turn_on_light(self):self.light.turn_on()def turn_on_fan(self):self.fan.turn_on()# 客戶端代碼
remote = RemoteControl()
remote.turn_on_fan()  # 輸出: The fan is ON

1.2.2 可擴展性

說明:可以輕松添加新的命令,而不需要修改現有代碼。只需創建新的命令類并實現命令接口即可。

示例代碼
# 新的具體命令類
class FanOffCommand(Command):def __init__(self, fan):self.fan = fandef execute(self):self.fan.turn_off()# 客戶端代碼
fan_off_command = FanOffCommand(fan)
fan_off_command.execute()  # 輸出: The fan is OFF

1.2.3 支持撤銷操作

說明:可以通過維護命令的歷史記錄來實現撤銷操作。每個命令對象可以記錄其執行的狀態,以便在需要時進行撤銷。

示例代碼
class CommandHistory:def __init__(self):self.history = []def push(self, command):self.history.append(command)def pop(self):if self.history:return self.history.pop()return None# 客戶端代碼
history = CommandHistory()# 執行命令
history.push(light_on_command)
light_on_command.execute()  # 輸出: The light is ON# 撤銷命令
last_command = history.pop()
if last_command:print("Undoing last command...")# 這里可以實現撤銷邏輯,例如不繪制圖形

1.2.4 支持隊列請求

說明:可以將請求放入隊列中,按順序執行。這使得命令模式非常適合處理異步請求或批量操作。

示例代碼
from collections import dequeclass CommandQueue:def __init__(self):self.queue = deque()def add_command(self, command):self.queue.append(command)def execute_commands(self):while self.queue:command = self.queue.popleft()command.execute()# 客戶端代碼
command_queue = CommandQueue()
command_queue.add_command(light_on_command)
command_queue.add_command(fan_on_command)# 執行所有命令
command_queue.execute_commands()
# 輸出:
# The light is ON
# The fan is ON

2. 示例 1:命令模式在文本編輯器中的應用

命令模式是一種強大的設計模式,能夠有效地解耦請求的發送者與接收者,提高代碼的靈活性和可維護性。在本文中,我們將通過一個文本編輯器的示例,展示如何使用命令模式來實現文本操作(如插入、刪除和撤銷)。

# 命令接口
class Command:def execute(self):passdef undo(self):pass# 接收者
class TextEditor:def __init__(self):self.text = ""def insert(self, text):self.text += textprint(f"Inserted: '{text}' | Current text: '{self.text}'")def delete(self, length):deleted_text = self.text[-length:] if length <= len(self.text) else self.textself.text = self.text[:-length]print(f"Deleted: '{deleted_text}' | Current text: '{self.text}'")# 具體命令類
class InsertCommand(Command):def __init__(self, editor, text):self.editor = editorself.text = textdef execute(self):self.editor.insert(self.text)def undo(self):self.editor.delete(len(self.text))class DeleteCommand(Command):def __init__(self, editor, length):self.editor = editorself.length = lengthself.deleted_text = ""def execute(self):self.deleted_text = self.editor.text[-self.length:] if self.length <= len(self.editor.text) else self.editor.textself.editor.delete(self.length)def undo(self):self.editor.insert(self.deleted_text)# 調用者
class CommandHistory:def __init__(self):self.history = []def push(self, command):self.history.append(command)def pop(self):if self.history:return self.history.pop()return Noneclass CommandQueue:def __init__(self):self.queue = []def add_command(self, command):self.queue.append(command)def execute_commands(self, history):while self.queue:command = self.queue.pop(0)command.execute()history.push(command)  # 將執行的命令添加到歷史記錄中# 客戶端代碼
if __name__ == "__main__":# 創建接收者editor = TextEditor()history = CommandHistory()command_queue = CommandQueue()# 創建并執行插入命令print("Executing insert commands:")insert_command1 = InsertCommand(editor, "Hello, ")command_queue.add_command(insert_command1)insert_command2 = InsertCommand(editor, "World!")command_queue.add_command(insert_command2)# 執行所有命令并記錄到歷史command_queue.execute_commands(history)# 預期輸出: "Inserted: 'Hello, ' | Current text: 'Hello, '"# 預期輸出: "Inserted: 'World!' | Current text: 'Hello, World!'"print(f"Current text after insertions: '{editor.text}'")  # 輸出: Hello, World!# 撤銷最后一個命令(插入)print("\nUndoing last insert command:")last_command = history.pop()if last_command:last_command.undo()  # 撤銷插入操作# 預期輸出: "Deleted: 'World!' | Current text: 'Hello, '"print(f"Current text after undo: '{editor.text}'")  # 輸出: Hello,# 創建并執行刪除命令print("\nExecuting delete command:")delete_command = DeleteCommand(editor, 6)command_queue.add_command(delete_command)command_queue.execute_commands(history)# 預期輸出: "Deleted: 'Hello, ' | Current text: ''"print(f"Current text after deletion: '{editor.text}'")  # 輸出: (空字符串)# 撤銷刪除命令print("\nUndoing delete command:")last_command = history.pop()if last_command:last_command.undo()  # 撤銷刪除操作# 預期輸出: "Inserted: 'Hello, ' | Current text: 'Hello, '"print(f"Current text after undo delete: '{editor.text}'")  # 輸出: Hello,# 最終狀態print(f"\nFinal text: '{editor.text}'")  # 輸出最終文本狀態
Executing insert commands:
Inserted: 'Hello, ' | Current text: 'Hello, '
Inserted: 'World!' | Current text: 'Hello, World!'
Current text after insertions: 'Hello, World!'Undoing last insert command:
Deleted: 'World!' | Current text: 'Hello, '
Current text after undo: 'Hello, 'Executing delete command:
Deleted: 'ello, ' | Current text: 'H'
Current text after deletion: 'H'Undoing delete command:
Inserted: 'ello, ' | Current text: 'Hello, '
Current text after undo delete: 'Hello, 'Final text: 'Hello, '
  1. 命令接口:定義了一個命令接口 Command,包含 executeundo 方法。所有具體命令類都需要實現這兩個方法。

  2. 接收者TextEditor 類是接收者,包含實際執行操作的方法 insertdelete。這些方法負責修改文本狀態并輸出當前文本。

  3. 具體命令類

    • InsertCommand 用于插入文本。它持有一個 TextEditor 對象的引用,并在 execute 方法中調用 insert 方法。在 undo 方法中調用 delete 方法以撤銷插入操作。
    • DeleteCommand 用于刪除文本。它同樣持有一個 TextEditor 對象的引用,并在 execute 方法中調用 delete 方法。在 undo 方法中調用 insert 方法以撤銷刪除操作。
  4. 調用者

    • CommandHistory 類用于維護命令的歷史記錄,以支持撤銷操作。它提供 pushpop 方法來管理命令歷史。
    • CommandQueue 類用于將命令放入隊列中,按順序執行,并在執行時將命令添加到歷史記錄中。
  5. 客戶端代碼:在客戶端代碼中,創建接收者、具體命令和調用者,并通過調用者執行命令。每個執行的命令都會被記錄到 CommandHistory 中,以便后續撤銷。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76814.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76814.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76814.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

nlp面試重點

深度學習基本原理&#xff1a;梯度下降公式&#xff0c;將損失函數越來越小&#xff0c;最終預測值和實際值誤差比較小。 交叉熵&#xff1a;-p(x)logq(x)&#xff0c;p(x)是one-hot形式。如果不使用softmax計算交叉熵&#xff0c;是不行的。損失函數可能會非常大&#xff0c;…

Leetcode:二叉樹

94. 二叉樹的中序遍歷 class Solution {public List<Integer> inorderTraversal(TreeNode root) {TreeNode cur root;Stack<TreeNode> stack new Stack<>();List<Integer> list new ArrayList<>();while (!stack.isEmpty() || cur ! null) {…

SQL:Constraint(約束)

目錄 &#x1f3af; 什么是 Constraint&#xff1f; MySQL 中常見的約束類型&#xff1a; 1. PRIMARY KEY 2. FOREIGN KEY 3. UNIQUE 4. NOT NULL 5. DEFAULT 6. CHECK&#xff08;MySQL 8.0&#xff09; 7. AUTO_INCREMENT &#x1f3af; 什么是 Constraint&#xf…

數據庫數據恢復——sql server數據庫被加密怎么恢復數據?

SQL server數據庫數據故障&#xff1a; SQL server數據庫被加密&#xff0c;無法使用。 數據庫MDF、LDF、log日志文件名字被篡改。 數據庫備份被加密&#xff0c;文件名字被篡改。 SQL server數據庫數據恢復過程&#xff1a; 1、將所有數據庫做完整只讀備份。后續所有數據恢…

MySQL 用 limit 影響性能的優化方案

一.使用索引覆蓋掃描 如果我們只需要查詢部分字段&#xff0c;而不是所有字段&#xff0c;我們可以嘗試使用索引覆蓋掃描&#xff0c;也就是讓查詢所需的所有字段都在索引中&#xff0c;這樣就不需要再訪問數據頁&#xff0c;減少了隨機 I/O 操作。 例如&#xff0c;如果我們…

【算法筆記】并查集詳解

&#x1f680; 并查集&#xff08;Union-Find&#xff09;詳解&#xff1a;原理、實現與優化 并查集&#xff08;Union-Find&#xff09;是一種非常高效的數據結構&#xff0c;用于處理動態連通性問題&#xff0c;即判斷若干個元素是否屬于同一個集合&#xff0c;并支持集合合…

鴻蒙HarmonyOS埋點SDK,ClkLog適配鴻蒙埋點分析

ClkLog埋點分析系統&#xff0c;是一種全新的、開源的洞察方案&#xff0c;它能夠幫助您捕捉每一個關鍵數據點&#xff0c;確保您的決策基于最準確的用戶行為分析。技術人員可快速搭建私有的分析系統。 ClkLog鴻蒙埋點SDK通過手動埋點的方式實現HarmonyOS 原生應用的前端數據采…

JMeter的關聯

關聯&#xff1a;上一個請求的響應結果和下一個請求的數據有關系 xpath提取器 適用場景 HTML/XML文檔結構化數據&#xff1a; 適用于從HTML或XML文檔中提取結構化數據。例如&#xff0c;提取表格中的數據、列表中的項目等。示例&#xff1a;從HTML表格中提取所有行數據。 …

Spring Security 權限配置詳解

&#x1f31f;Spring Security 權限配置詳解&#xff1a;從基礎到進階 Spring Security 是一個功能強大、可高度自定義的安全框架&#xff0c;主要用于為基于 Spring 的應用程序提供身份驗證和授權功能。 本篇文章將帶你深入理解 Spring Security 的權限配置機制&#xff0c;掌…

pycharm中安裝Charm-Crypto

一、安裝依賴 1、安裝gcc、make、perl sudo apt-get install gcc sudo apt-get install make sudo apt-get install perl #檢查版本 gcc -v make -v perl -v 2、安裝依賴庫m4、flex、bison(如果前面安裝過pypbc的話,應該已經裝過這些包了) sudo apt-get update sudo apt…

【MCAL】AUTOSAR架構下基于SPI通信的驅動模塊詳解-以TJA1145為例

目錄 前言 正文 1.TJA1145驅動代碼中的SPI協議設計 1.1 對SPI Driver的依賴 1.2 對SPI配置的依賴 1.2.1 SpiExternalDevice 1.2.2 Channel_x 1.2.3 Job_x 1.2.4 Sequence N 1.2.5 Sequence M 1.2.6 Sequence L 1.2.7 小結 2.基于Vector驅動代碼的SPI配置 2.1 SPI引…

JavaScript:BOM編程

今天我要介紹的是JS中有關于BOM編程的知識點內容&#xff1a;BOM編程&#xff1b; 介紹&#xff1a;BOM全名&#xff08;Browser Object Model&#xff08;瀏覽器對象模型&#xff09;&#xff09;。 是瀏覽器提供的與瀏覽器窗口交互的接口&#xff0c;其核心對象是 window。與…

Memcached緩存系統:從部署到實戰應用指南

#作者&#xff1a;獵人 文章目錄 一、安裝libevent二、安裝配置memcached三、安裝Memcache的PHP擴展四、使用libmemcached的客戶端工具五、Nginx整合memcached:六、php將會話保存至memcached Memcached是一款開源、高性能、分布式內存對象緩存系統&#xff0c;可應用各種需要緩…

解決前后端時區不一致問題

前后端時區不一致導致&#xff1a; 》數據不顯示在前端 》頁面顯示時間有誤 》一些對時間有要求的方法&#xff0c;無法正確執行&#xff0c;出現null值&#xff0c;加上我們對null值有判斷/注解&#xff0c;程序就會報錯中斷&#xff0c;以為是業務邏輯問題&#xff0c;其實…

35.Java線程池(線程池概述、線程池的架構、線程池的種類與創建、線程池的底層原理、線程池的工作流程、線程池的拒絕策略、自定義線程池)

一、線程池概述 1、線程池的優勢 線程池是一種線程使用模式&#xff0c;線程過多會帶來調度開銷&#xff0c;進而影響緩存局部性和整體性能&#xff0c;而線程池維護著多個線程&#xff0c;等待著監督管理者分配可并發執行的任務&#xff0c;這避免了在處理短時間任務時創建與…

驅動開發硬核特訓 · Day 6 : 深入解析設備模型的數據流與匹配機制 —— 以 i.MX8M 與樹莓派為例的實戰對比

&#x1f50d; B站相應的視屏教程&#xff1a; &#x1f4cc; 內核&#xff1a;博文視頻 - 從靜態綁定驅動模型到現代設備模型 主題&#xff1a;深入解析設備模型的數據流與匹配機制 —— 以 i.MX8M 與樹莓派為例的實戰對比 在上一節中&#xff0c;我們從驅動框架的歷史演進出…

Blender安裝基礎使用教程

本博客記錄安裝Blender和基礎使用&#xff0c;可以按如下操作來繪制標靶場景、道路標識牌等。 目錄 1.安裝Blender 2.創建面板資源 步驟 1: 設置 Blender 場景 步驟 2: 創建一個平面 步驟 3: 將 PDF 轉換為圖像 步驟 4-方法1: 添加材質并貼圖 步驟4-方法2&#xff1a;創…

智能手機功耗測試

隨著智能手機發展,用戶體驗對手機的續航功耗要求越來越高。需要對手機進行功耗測試及分解優化,將手機的性能與功耗平衡。低功耗技術推動了手機的用戶體驗。手機功耗測試可以采用powermonitor或者NI儀表在功耗版上進行測試與優化。作為一個多功能的智能終端,手機的功耗組成極…

從代碼學習深度學習 - 多頭注意力 PyTorch 版

文章目錄 前言一、多頭注意力機制介紹1.1 工作原理1.2 優勢1.3 代碼實現概述二、代碼解析2.1 導入依賴序列掩碼函數2.2 掩碼 Softmax 函數2.3 縮放點積注意力2.4 張量轉換函數2.5 多頭注意力模塊2.6 測試代碼總結前言 在深度學習領域,注意力機制(Attention Mechanism)是自然…

學術版 GPT 網頁

學術版 GPT 網頁 1. 學術版 GPT 網頁非盈利版References https://academic.chatwithpaper.org/ 1. 學術版 GPT 網頁非盈利版 arXiv 全文翻譯&#xff0c;免費且無需登錄。 更換模型 System prompt: Serve me as a writing and programming assistant. 界面外觀 References …