設計模式在軟體開發中扮演著重要角色,能有效提升程式碼的重用性、可讀性和可維護性。本文將聚焦於行為設計模式,深入探討解讀器模式、策略模式、備忘錄模式以及迭代器模式,並結合 Python 程式碼範例進行實作說明。這些模式各有其應用場景和優缺點,理解它們的特性有助於開發者在實際專案中做出更明智的設計決策。透過 Pyparsing 函式庫,示範如何定義語法結構並解析事件,實作靈活的事件處理系統。策略模式則以排序演算法為例,展示如何在執行期動態切換不同演算法,提高程式彈性。備忘錄模式則利用 pickle 模組簡化物件狀態的儲存與還原,適用於復原/重做等功能。最後,迭代器模式則以自定義迭代器示範如何簡化集合物件的遍歷過程,提升程式碼的可讀性。
行為設計模式:解讀器模式與策略模式
解讀器模式:實作自定義事件處理
解讀器模式是一種能夠解讀特定語法結構並執行對應動作的設計模式。在實際應用中,我們可以利用此模式建立一個簡單的事件處理系統。
使用Pyparsing實作事件解析
首先,我們需要匯入Pyparsing函式庫來定義事件的語法結構。以下是一個簡單的事件語法定義範例:
from pyparsing import Word, Suppress, Group, OneOrMore, Optional
# 定義基本元素
word = Word(alphas)
token = Suppress("->")
device = Group(OneOrMore(word))
argument = Group(OneOrMore(word))
command = word
event = command + token + device + Optional(token + argument)
事件解析與執行
定義好事件語法後,我們可以對輸入的字串進行解析並執行對應的動作:
boiler = Boiler()
test = "increase -> boiler temperature -> 3 degrees"
cmd, dev, arg = event.parseString(test)
cmd_str = " ".join(cmd)
dev_str = " ".join(dev)
if "increase" in cmd_str and "boiler" in dev_str:
boiler.increase_temperature(int(arg[0]))
print(boiler)
內容解密:
此程式碼實作了解讀器模式的核心功能。首先定義事件的語法結構,然後解析輸入字串並根據解析結果執行對應的動作。透過這種方式,我們可以實作一個靈活的事件處理系統。
解讀器模式的實際應用
在實際應用中,我們可以擴充套件解讀器模式以支援更多型別的事件和裝置。以下是一個更完整的實作範例:
# 定義各種裝置類別
class Gate:
def open(self):
print("開啟大門")
class Aircondition:
def turn_on(self):
print("開啟冷氣")
# 主函式實作
def main():
tests = [
"open -> gate",
"turn on -> air condition"
]
for test in tests:
# 解析事件並執行對應動作
cmd, dev, arg = event.parseString(test)
# ... 省略執行邏輯
if __name__ == "__main__":
main()
圖表說明:解讀器模式流程
圖表翻譯:
此圖示展示瞭解讀器模式的處理流程。首先接收事件輸入,然後進行語法解析。如果解析成功,則執行對應的動作;若解析失敗,則進行錯誤處理。最後輸出處理結果。
策略模式:動態選擇演算法
策略模式是一種允許在執行時動態選擇演算法的設計模式。這種模式特別適用於需要根據不同條件選擇不同實作方案的場景。
策略模式的實際應用
在實際應用中,策略模式可以用於實作不同的排序演算法。以下是一個簡單的範例:
# 定義排序策略介面
def bubble_sort(data):
# 氣泡排序實作
pass
def quick_sort(data):
# 快速排序實作
pass
# 根據資料大小選擇排序策略
def sort_data(data):
if len(data) < 10:
return bubble_sort(data)
else:
return quick_sort(data)
策略模式的優點
- 靈活性:可以在執行時動態選擇演算法
- 可擴充套件性:可以輕易新增新的演算法實作
- 維護性:不同的演算法實作相互獨立,便於維護
圖表說明:策略模式結構
圖表翻譯:
此圖示展示了策略模式的典型結構。Context類別負責維護目前使用的策略,並透過Strategy介面呼叫具體的演算法實作。不同的具體策略(ConcreteStrategyA和ConcreteStrategyB)實作了不同的演算法。透過這種設計,可以在執行時動態切換不同的演算法實作。
策略模式(Strategy Pattern)詳解
策略模式是一種行為設計模式,允許在執行時選擇物件的行為或演算法。它定義了一系列演算法,將每個演算法封裝起來,並使它們可以相互替換。該模式讓演算法的變化獨立於使用演算法的客戶端。
問題背景
假設我們需要實作一個演算法來檢查字串中的所有字元是否唯一。我們可以採用不同的演算法來實作這一目標,例如透過排序字串或使用集合資料結構。
策略模式的應用
首先,我們實作pairs()函式,該函式傳回序列中所有相鄰元素對:
def pairs(seq):
n = len(seq)
for i in range(n):
yield seq[i], seq[(i + 1) % n]
接著,我們實作兩個不同的演算法:allUniqueSort()和allUniqueSet()。
allUniqueSort()演算法
該演算法透過排序字串並比較相鄰字元來檢查字串中的字元是否唯一。對於較長的字串,該演算法會模擬一個緩慢的執行過程:
SLOW = 3 # 模擬延遲時間(秒)
LIMIT = 5 # 字串長度限制
WARNING = "太糟糕了,您選擇了慢速演算法"
def allUniqueSort(s):
if len(s) > LIMIT:
print(WARNING)
time.sleep(SLOW)
srtStr = sorted(s)
for c1, c2 in pairs(srtStr):
if c1 == c2:
return False
return True
allUniqueSet()演算法
該演算法使用集合資料結構來檢查字串中的字元是否唯一。對於較短的字串,該演算法會模擬一個緩慢的執行過程:
def allUniqueSet(s):
if len(s) < LIMIT:
print(WARNING)
time.sleep(SLOW)
return len(set(s)) == len(s)
策略選擇
我們定義allUnique()函式,該函式接受輸入字串和策略函式,並執行所選的策略:
def allUnique(s, strategy):
return strategy(s)
使用者互動
在main()函式中,我們允許使用者輸入字串並選擇要使用的策略:
def main():
while True:
word = input("輸入單字(輸入 quit 離開)> ")
if word == "quit":
print("再見")
return
strategy_picked = input("選擇策略:[1] 使用集合,[2] 排序並比較> ")
strategies = {"1": allUniqueSet, "2": allUniqueSort}
try:
strategy = strategies[strategy_picked]
result = allUnique(word, strategy)
print(f"allUnique({word}): {result}")
except KeyError:
print(f"錯誤的選項:{strategy_picked}")
執行結果
執行範例輸出如下:
輸入單字(輸入 quit 離開)> balloon
選擇策略:[1] 使用集合,[2] 排序並比較> 1
太糟糕了,您選擇了慢速演算法
allUnique(balloon): False
輸入單字(輸入 quit 離開)> balloon
選擇策略:[1] 使用集合,[2] 排序並比較> 2
allUnique(balloon): False
輸入單字(輸入 quit 離開)> bye
選擇策略:[1] 使用集合,[2] 排序並比較> 1
allUnique(bye): True
輸入單字(輸入 quit 離開)> bye
選擇策略:[1] 使用集合,[2] 排序並比較> 2
allUnique(bye): True
策略模式的優點
策略模式允許在執行時動態選擇演算法,提高了程式的靈活性和可擴充套件性。透過封裝不同的演算法,我們可以輕鬆地新增或替換演算法,而無需修改客戶端程式碼。
Memento 模式簡介
Memento 模式是一種行為設計模式,用於捕捉物件的內部狀態,以便稍後將物件還原到該狀態。該模式包含三個主要元件:Memento、Originator 和 Caretaker。
Memento 模式的應用場景
Memento 模式在許多情況下非常有用,例如在需要實作復原/重做功能時。該模式允許我們儲存物件的歷史狀態,並在需要時還原到之前的狀態。
圖表翻譯:
此圖示展示了根據字串長度選擇不同策略的流程。流程首先檢查輸入字串的長度,如果長度超過限制,則選擇allUniqueSort演算法;否則,選擇allUniqueSet演算法。最後,傳回所選演算法的執行結果。該圖清晰地展示了策略模式在不同場景下的應用。
備忘錄模式在軟體開發中的應用
在軟體開發領域中,備忘錄(Memento)模式是一種常見的設計模式,主要用於實作物件狀態的儲存與還原功能。備忘錄模式在需要提供復原(Undo)和重做(Redo)功能的應用程式中非常有用。
備忘錄模式的使用場景
- 復原和重做功能:備忘錄模式最典型的應用場景是實作復原和重做功能。透過儲存物件的不同狀態,使用者可以輕鬆地在不同狀態之間切換。
- 對話方塊狀態儲存:在具有確定和取消按鈕的對話方塊中,可以使用備忘錄模式儲存物件的初始狀態。如果使用者選擇取消,物件的狀態可以還原到初始狀態。
實作備忘錄模式
在Python中,可以利用pickle模組簡化備忘錄模式的實作。pickle模組能夠將複雜的物件轉換為位元組流,並能夠將位元組流還原為具有相同內部結構的物件。
使用pickle實作備忘錄模式
import pickle
class Quote:
def __init__(self, text, author):
self.text = text
self.author = author
def save_state(self):
"""儲存物件當前狀態"""
current_state = pickle.dumps(self.__dict__)
return current_state
def restore_state(self, memento):
"""還原物件狀態"""
previous_state = pickle.loads(memento)
self.__dict__.clear()
self.__dict__.update(previous_state)
def __str__(self):
return f"{self.text}\n- By {self.author}."
def main():
print("** Quote1 **")
q1 = Quote(
"A room without books is like a body without a soul.",
"Unknown author",
)
print(f"\nOriginal version:\n{q1}")
q1_mem = q1.save_state()
# 發現作者姓名後更新
q1.author = "Marcus Tullius Cicero"
print(f"\nWe found the author, and did an updated:\n{q1}")
# 還原先前的狀態(復原)
q1.restore_state(q1_mem)
print(f"\nWe had to restore the previous version:\n{q1}")
if __name__ == "__main__":
main()
程式碼解析
Quote類別定義:定義了一個Quote類別,包含text和author屬性。save_state方法:使用pickle.dumps將物件的當前狀態儲存為位元組流。restore_state方法:使用pickle.loads將儲存的狀態還原到物件中。main函式:示範瞭如何使用Quote類別並透過備忘錄模式儲存和還原物件狀態。
迭代器模式簡介
迭代器(Iterator)模式是一種行為設計模式,主要用於遍歷集合物件中的元素,而無需暴露其底層實作。
迭代器模式的使用場景
- 遍歷集合物件:迭代器模式使得遍歷集合物件變得更加容易。
- 取得下一個物件:可以在任何時候取得集合中的下一個物件。
- 停止遍歷:當遍歷完成時,可以停止迭代。
在Python中實作迭代器模式
Python內建支援迭代器模式,可以透過實作__iter__和__next__方法來建立自定義迭代器。
自定義迭代器範例
class FootballTeamIterator:
def __init__(self, members):
self.members = members
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.members):
val = self.members[self.index]
self.index += 1
return val
else:
raise StopIteration
# 使用範例
team_members = ["Player1", "Player2", "Player3"]
team_iterator = FootballTeamIterator(team_members)
for member in team_iterator:
print(member)
Plantuml迭代器模式流程
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 行為設計模式解讀器策略與備忘錄模式
package "Python 應用架構" {
package "應用層" {
component [主程式] as main
component [模組/套件] as modules
component [設定檔] as config
}
package "框架層" {
component [Web 框架] as web
component [ORM] as orm
component [非同步處理] as async
}
package "資料層" {
database [資料庫] as db
component [快取] as cache
component [檔案系統] as fs
}
}
main --> modules : 匯入模組
main --> config : 載入設定
modules --> web : HTTP 處理
web --> orm : 資料操作
orm --> db : 持久化
web --> cache : 快取查詢
web --> async : 背景任務
async --> fs : 檔案處理
note right of web
Flask / FastAPI / Django
end note
@enduml圖表解析
此圖表展示了迭代器模式的基本流程。迭代過程從「開始迭代」開始,首先檢查是否還有元素可供迭代。如果有,則傳回下一個元素並繼續檢查;如果沒有,則丟擲StopIteration異常以表示迭代結束。