命令設計模式簡介
行爲模式側重於對象的響應性,它利用對象之間的交互實現更強大的功能。命令模式也是一種行爲設計模式,其中對象用於封裝在完成一項操作時或在觸發一個事件時所需的全部信息。
命令模式通常使用以下術語:Command、Receiver、Invoker和Client:
1、Command對象瞭解Receiver對象的情況,並能調用Receiver對象的方法
2、調用者方法的參數值存儲在Command對象中
3、調用者知道如何執行命令
4、客戶端用來創建Command對象並設置其接收者
命令模式的主要意圖如下:
1、將請求封裝爲對象
2、可用不同的請求對客戶進行參數化
3、允許將請求保存在隊列中
4、提供面向對象的回調
命令模式可用於以下各種場景:
1、根據需要執行的操作對對象進行參數化
2、將操作添加到隊列並在不同地點執行請求
3、創建一個結構來根據較小操作完成高級操作
class Wizard(object):
def __init__(self, src, root_dir):
self.choices = []
self.root_dir = root_dir
self.src = src
def preferences(self, command):
self.choices.append(command)
def execute(self):
for choice in self.choices:
if list(choice.values())[0]:
print("Copying binaries --", self.src, " to ", self.root_dir)
else:
print("No Operation")
if __name__ == "__main__":
wizard = Wizard('python3', '/usr/bin')
wizard.preferences({'python': True})
wizard.preferences({'java': False})
wizard.execute()
以上的Python代碼實現了命令設計模式。
命令設計模式主要涉及5個參與者:
1、Command:聲明執行操作的接口
2、ConcreteCommand:將一個Receiver對象和一個操作綁定在一起
3、Client:創建ConcreteCommand執行這個請求
4、Invoker:要求該ConcreteCommand執行這個請求
5、Receiver:知道如何實施與執行一個請求相關的操作
整個流程非常簡單的,客戶端請求執行命令,調用者接受命令,封裝它並將其放置到隊列中。ConcreteCommand類根據所請求得命令來指導接收者執行特定得動作。通過以下代碼,可以幫助我們進一步瞭解該模式中所有參與者得情況:
from abc import ABCMeta, abstractmethod
class Command(metaclass=ABCMeta):
def __init__(self, recv):
self.recv = recv
def execute(self):
pass
class ConcreteCommand(Command):
def execute(self):
self.recv.action()
class Receiver(object):
def action(self):
print("Receiver Action")
class Invoker(object):
def command(self, cmd):
self.cmd = cmd
def execute(self):
self.cmd.execute()
if __name__ == '__main__':
recv = Receiver()
cmd = ConcreteCommand(recv)
invoker = Invoker()
invoker.command(cmd)
invoker.execute()
實現生活中得命令模式
我們通過一個證券交易所得例子來演示命令模式得實現。作爲證券交易得用戶,你會創建買入或者賣出得股票訂單。通常情況下,你無法執行買入或者賣出。實際上,代理或者經紀人,在你和證券交易所之間扮演了中介得角色。代理負責將你得請求提交給證券交易所,完成工作。我們假設你想在星期一早上開市後賣出股票。但是在週日晚上,雖然交易所尚未開市,你就可以向代理提出賣出股票得請求。然後代理會將該請求放入排隊,以便在週一早上交易所開放得時候執行請求。這實際上就是一個命令模式得經典情形。
下面,利用Python開放一個應用程序,並實現前面得用例:
我們首先介紹Command對象,即Order:
1、Command對象由Order類表示
2、Order提供一個接口,以便於ConcreteCommand可以實現該行爲
3、execute()方法是需要由執行Order類得ConcreteCommand類來定義的抽象方法
下面的代碼提供了抽象類Order和抽象方法execute()
from abc import ABCMeta, abstractmethod
class Order(metaclass=ABCMeta):
@abstractmethod
def execute(self):
pass
我們還開發可表示ConcreteCommand的某些類:
1、這裏,我們有兩個主要的具體類:BuyStockOrder和 ShellStockOrder,它們實現了Order接口
2、這兩個ConcreteCommand類都使用股票交易系統的對象,所以它們可以爲交易系統定義適當的操作
3、每個ConcreteCommand類的execute()方法使用股票交易對象執行買入和賣出的操作
class BuyStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.buy()
class SellStockOrder(Order):
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.sell()
現在。我們討論股票交易系統及其實現:
1、StockTrade類表示該示例中的Receiver對象
2、它定義了多個方法來執行ConcreteCommand對象發出的訂單
3、buy()和sell()方法由接收者定義,分別由BuyStockOrder和SellStockOrder調用以在交易所中買入或賣出股票
讓我們來看看StockTrade類:
class StockTrade(object):
def buy(self):
print("你要買股票")
def sell(self):
print("你要賣股票")
另一部分代碼是關於調用者的:
1、Agent類表示調用者
2、代理時客戶端和StockExchange之間的中介,並執行客戶下達的訂單
3、代理定義了一個作爲隊列的數據成員__order_queue,客戶端下達的任何新訂單都將添加到隊列中
4、代理的place_order()方法負責對訂單排序以及執行訂單
以下代碼描述了扮演調用者角色的Agent類:
class Agent(object):
def __init__(self):
self.__order_queue = []
def place_order(self, order):
self.__order_queue.append(order)
order.execute()
以下是客戶端的實現代碼:
if __name__ == "__main__":
# Client
stock = StockTrade()
buy_stock = BuyStockOrder(stock)
sell_stock = SellStockOrder(stock)
# Invoker
agent = Agent()
agent.place_order(buy_stock)
agent.place_order(sell_stock)
在軟件中應用命令模式的方式有很多種。我們將討論與雲應用密切相關的兩個實現。
重做或回滾操作:
1、在實現回滾或重做操作時,開發人員可以做兩件不同的事情;
2、這些是在文件系統或內存中創建快照,當要求被回滾時,恢復到該快照;
3、使用命令模式時,可以存儲命令序列,並且要求進行重做時,重新運行相同的一組操作即可。
異步任務執行:
1、在分佈式系統中嗎,我們通常要求設備具備異步執行任務的功能,以便核心服務在大量請求涌來時不會發生阻塞。
2、載命令模式中,Invoker對象可以維護一個請求隊列,並將這些任務發送到Receiver對象,以便它們可以獨立於主應用程序線程來完成相應的操作。
命令模式的優缺點
優點:
1、將調用操作的類與知道如何執行該操作的對象解耦;
2、提供隊列系統後,可以創建一系列命令;
3、添加新命令更加容易,並且無需更改現有的代碼
4、還可以使用命令模式來定義回滾系統
命令模式的缺點:
1、爲了實現目標,需要大量的類和對象進行協作。應用程序開發人員爲了正確開發這些類,需要加倍小心
2、每個單獨的命令都是一個ConcreteCommand類,從而增加了需要實現和維護的類的數量