第23章:命令模式
當請求排隊或記錄請求日誌,以及支持可撤銷的操作等行爲時,行爲請求者
與行爲實現者
的緊耦合並不適合。
命令模式
命令(command)模式:將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤銷的操作。
Command
類,用來聲明執行操作的接口。
ConcreteCommand
類,將一個接收者對象綁定於一個動作,調用接收者相應的操作,以實現Execute
。
Invoker
類,要求該命令執行這個請求。
Receiver
類,知道如何實施與執行一個與請求相關的操作,任何類都可能作爲一個接收者。
客戶端代碼,創建一個具體命令對象並設定它的接收者。
命令模式作用
-
能較容易地設計一個命令隊列;
-
在需要的情況下,可以較容易地將命令記入日誌;
-
允許接收請求的一方決定是否要否決請求;
-
可以容易地實現對請求的撤銷和重做;
-
由於加進新的具體命令類不影響其他的類,因此增加新的具體命令類很容易。
命令模式把請求一個操作的對象與知道怎麼執行一個操作的對象分割開。
敏捷開發原則:不要爲代碼添加基於猜測的、實際不需要的功能。 如果不清楚一個系統是否需要命令模式,一般就不要着急去實現它,事實上,在需要的時候通過重構實現這個模式並不困難,只有在真正需要如撤銷/恢復操作等功能時,把原來的代碼重構爲命令模式纔有意義。
命令模式示例
任務:烤串下單
緊耦合v.s.鬆耦合
緊耦合
鬆耦合
from abc import ABCMeta, abstractmethod
from typing import Text
import datetime
class Barbecuer(object):
"""
烤肉串者(Receiver)類
"""
def bake_mutton(self) -> None:
print("烤羊肉串!")
def bake_chicken_wing(self) -> None:
print("烤雞翅!")
class Command(metaclass=ABCMeta):
"""
抽象命令(Command)類
"""
def __init__(self, receiver: Barbecuer) -> None:
self._receiver = receiver
@abstractmethod
def excute_command(self) -> None:
pass
@abstractmethod
def __str__(self) -> Text:
pass
class BakeMuttonCommand(Command):
"""
烤羊肉串命令類
"""
def excute_command(self) -> None:
self._receiver.bake_mutton()
def __str__(self) -> Text:
return "烤羊肉串"
class BakeChickenWingCommand(Command):
"""
烤雞翅命令類
"""
def excute_command(self) -> None:
self._receiver.bake_chicken_wing()
def __str__(self) -> Text:
return "烤雞翅"
class Waiter(object):
"""
服務員(Invoker)類
"""
def __init__(self) -> None:
self.__orders = []
def set_order(self, command: Command):
if str(command) == "烤雞翅":
print("服務員:雞翅沒有了,請點別的燒烤。")
else:
self.__orders.append(command)
print("增加訂單:{},時間:{}".format(str(command), datetime.datetime.now()))
def cancel_order(self, command: Command) -> None:
self.__orders.remove(command)
print("取消訂單:{},時間:{}".format(str(command), datetime.datetime.now()))
def notify(self):
"""
通知執行
"""
for cmd in self.__orders:
cmd.excute_command()
# 客戶端代碼實現
if __name__ == "__main__":
# 開店前的準備
boy = Barbecuer()
bake_mutton_command = BakeMuttonCommand(boy)
bake_chicken_wing_command = BakeChickenWingCommand(boy)
girl = Waiter()
# 開門營業顧客點菜
girl.set_order(bake_mutton_command)
girl.set_order(bake_mutton_command)
girl.set_order(bake_chicken_wing_command)
# 點菜完閉,通知廚房
girl.notify()
增加訂單:烤羊肉串,時間:2020-05-09 11:40:08.302918
增加訂單:烤羊肉串,時間:2020-05-09 11:40:08.302918
服務員:雞翅沒有了,請點別的燒烤。
烤羊肉串!
烤羊肉串!