在軟體工程中,“行為請求者”與“行為實現者”通常呈現“高耦合”。
但有時候,如要對行為進行“記錄、撤銷/重做、事務”等處理,這種無法抵禦變化的高耦合是不合適的。
如何將“行為請求者”與“行為實現者”解耦,將一組行為抽象為對象,實現二者之間的松耦合?
"利用Invoker與Command",這就是命令模式(Command Pattern)。
這些都是啥?真得很亂阿!沒關係不重要,直接看看生活中的例子!
from abc import ABC, abstractmethod
import queue
class 顧客:
def __init__(self,nickname):
print(nickname)
def eat(self,meal):
return meal
class 一蘭拉麵:
def __init__(self):
#一蘭拉麵店員跟師傅合作點餐跟出餐
self.invoker = 店員()
#一蘭拉麵師傅做拉麵
self.receiver = 師傅()
#一蘭拉麵有賣師傅做的豚骨拉麵
self.concreteCommand_豚骨拉麵 = 一份豚骨拉麵(self.receiver)
#一蘭拉麵有賣師傅做的醬油拉麵
self.concreteCommand_醬油拉麵 = 一份醬油拉麵(self.receiver)
print("一蘭拉麵公告,疫情關係,由店員按自助點餐機")
def order(self,meal):
if meal=="豚骨拉麵":
self.invoker.確認餐點命令(self.concreteCommand_豚骨拉麵)
self.invoker.出餐()
else:
self.invoker.確認餐點命令(self.concreteCommand_醬油拉麵)
self.invoker.出餐()
print("點了一份 %s" % meal)
class 店員:
commandorders = queue.Queue()
def __init__(self,):
self.name = "店小二"
# print(self.name)
# 將餐點命令放入commandorders隊列
def 確認餐點命令(self,點餐機):
self.commandorders.put(點餐機)
# 將餐點命令移出commandorders隊列
def 取消餐點命令(self,點餐機):
self.commandorders.get(點餐機)
# 請師傅開始製作,並將餐點命令移出commandorders隊列
def 出餐(self):
while self.commandorders.empty():
concreteCommand = self.commandorders.get(點餐機)
concreteCommand.exeute()
class 師傅:
def __init__(self):
self.name = "陳師傅"
# print(self.name)
def 製作豚骨拉麵(self):
print("%s 開始製作豚骨拉麵" %self.name)
def 製作醬油拉麵(self):
print("%s 開始製作醬油拉麵" %self.name)
class 點餐機(ABC): # 命令:抽象類
@abstractmethod
def execute(self):
"""做什麼拉麵"""
class 一份豚骨拉麵(點餐機): # 命令:實作類
def __init__(self,receiver):
self.name = "一份豚骨拉麵"
self.receiver=師傅()
# print(self.name)
def execute(self):
self.receiver.製作豚骨拉麵()
class 一份醬油拉麵(點餐機): # 命令:實作類
def __init__(self,receiver):
self.name = "一份醬油拉麵"
self.receiver=師傅()
# print(self.name)
def execute(self):
self.receiver.製作醬油拉麵()
if __name__=="__main__":
client = 一蘭拉麵()
顧客("吃貨小明").eat(client.order("豚骨拉麵"))
小明去"一蘭拉麵",想要點一碗豚骨拉麵,但是疫情關係,現在皆由"店員"操作點餐機,店員開始操作點餐機:
"點餐機"上面有好多命令,其中有一項是"一碗豚骨拉麵",店員確認小明要點一碗豚骨拉麵,請"師傅"做了一碗豚骨拉麵後,小明自取。
點餐機:這就是上述架構圖的"Command",點餐機上面可以有很多餐點命令(所以是抽象類,因為有很多餐點命令)。
一份豚骨拉麵:這就是上述架構圖的"ConcreteCommand",在點餐機上,除了有一份豚骨拉麵,也有一份醬油拉麵,一份地獄拉麵...,然而這只是命令,真正實作的是"師傅(Receiver)"。
師傅:這就是上述架構圖的"Receiver"(行為實作者),師傅就負責實作,至於要做什麼?ConcreteCommand派師傅做什麼就做什麼
店員:這就是上述架構圖的"Invoker"!店員確認要點一份豚骨拉麵,還是一份醬油拉麵,店員可以決定出餐順序/要不要出餐:
也就是究竟命令要不要做,什麼時候做,全都可以由Invoker控制!
一蘭拉麵:這就是上述架構圖的"Client"",擁有上述所有實體類(點餐機是抽象類)的類(行為請求者)
這樣是不是更好理解呢,總之,以上這種模式就是命令模式:
Client要進行生產(拉麵),是叫 Invoker ConcreteCommand(Command) Receiver 去煮要生產的各種拉麵。
註:[附上找到的優缺點與使用時機,供參考,依照情況彈性使用](https://baike.baidu.com/item/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F/7277118)
Reference:
https://blog.xuite.net/rubyintainan/blog/324083320 https://zh.wikipedia.org/zh-tw/%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F https://www.runoob.com/design-pattern/command-pattern.html https://notfalse.net/4/command-pattern#i-11
Share on Twitter Share on FacebookSQL Server Analytics Service 1
SEO(1) Github(2) Title Tag(2) ML(1) 李宏毅(1) SQL Server(18) Tempdb(1) SSMS(1) Windows(1) 自我成長(2) Excel(1) python Flask(1) python(5) Flask(2)
Max Chen (159)