命令模式是將一次完整的業務處理拆成了提出業務和處理業務兩部分,這個模式把提出業務稱爲發起命令,處理業務稱爲執行命令。同時,提出業務與處理業務的解耦,暗含着一種異步的思想。
“命令”一詞,聽起來很拽的感覺,調用方(Invoker)只管發起命令(Command),不參與命令如何被執行(Receiver)。既然這麼拽,我們就拿皇帝的聖旨來做例子好了。首先,我們看下UML圖:
等等,這是不是與書上和網上的UML圖不一樣?Client哪去了?我們先看看一般文章中的類圖長什麼樣:
這個圖往往容易誤導讀者,讓人以爲Client就是調用方。事實上Client只是提供了一個Invoker、Command和Receiver的場景,用Context來定義它更爲合理。不管怎麼說,場景類只是輔助,模式的本質還是第一張UML圖。
下面我們用代碼來實現。首先給出實際案例:公元前119年,漢武帝派衛青、霍去病兩路大軍,分別去滅掉匈奴主力與匈奴王庭。起初,漢武帝給出的命令是霍去病攻打匈奴主力,衛青負責匈奴王庭。然而在北征的途中,卻是衛青遇到了匈奴主力,霍去病碰到了匈奴老窩。兩人分別派信使通報了皇帝情況,皇帝則頒佈了新的命令,將二人的攻打對象調換。
先定義兩位Receiver(衛青、霍去病),以及他們的行爲:
# 命令接收者 - 衛青
class WeiQingReceiver(Singleton):
def attack_main_force(self):
print('衛青:我現在去攻打匈奴主力')
def attack_palace(self):
print('衛青:我現在去攻打匈奴王庭')
def stop_attack_main_force(self):
print('衛青:我已停止攻打匈奴主力')
def stop_attack_palace(self):
print('衛青:我已停止攻打匈奴王庭')
# 命令接收者 - 霍去病
class HuoQuBingReceiver:
def attack_main_force(self):
print('霍去病:我現在去攻打匈奴主力')
def attack_palace(self):
print('霍去病:我現在去攻打匈奴王庭')
def stop_attack_main_force(self):
print('霍去病:我已停止攻打匈奴主力')
def stop_attack_palace(self):
print('霍去病:我已停止攻打匈奴王庭')
定義命令發佈者Invoker(漢武帝):
# 漢武帝 - Invoker
class HanWuDiInvoker:
_command = None
def set_command(self, _command):
self._command = _command
def issue_command(self):
self._command.execute()
def undo_command(self):
self._command.undo()
接下來定義抽象命令類,及4個具體的命令類(衛青攻打王庭、衛青攻打主力、霍去病攻打王庭、霍去病攻打主力)
# 抽象命令類
class AbstractCommand:
def execute(self):
pass
def undo(self):
pass
# 具體命令類 - 衛青攻打匈奴主力
class WeiQingAttackMainForceCommand:
__weiqing = WeiQingReceiver()
def execute(self):
self.__weiqing.attack_main_force()
def undo(self):
self.__weiqing.stop_attack_main_force()
# 具體命令類 - 衛青攻打匈奴王庭
class WeiQingAttackPalaceCommand:
__weiqing = WeiQingReceiver()
def execute(self):
self.__weiqing.attack_palace()
def undo(self):
self.__weiqing.stop_attack_palace()
# 具體命令類 - 霍去病攻打匈奴主力
class HuoQuBingAttackMainForceCommand:
__huoqubing = HuoQuBingReceiver()
def execute(self):
self.__huoqubing.attack_main_force()
def undo(self):
self.__huoqubing.stop_attack_main_force()
# 具體命令類 - 霍去病攻打匈奴王庭
class HuoQuBingAttackPalaceCommand:
__huoqubing = HuoQuBingReceiver()
def execute(self):
self.__huoqubing.attack_palace()
def undo(self):
self.__huoqubing.stop_attack_palace()
最後構造場景:
if __name__ == '__main__':
hanWuDi = HanWuDiInvoker()
print('1.漢武帝發佈命令:衛青攻打匈奴王庭,霍去病攻打匈奴主力。')
command1 = WeiQingAttackPalaceCommand()
hanWuDi.set_command(command1)
hanWuDi.issue_command()
command2 = HuoQuBingAttackMainForceCommand()
hanWuDi.set_command(command2)
hanWuDi.issue_command()
print()
print('2.衛青中途遇到了匈奴主力,請示皇帝后,皇帝頒發了新的命令:衛青攻打匈奴主力')
hanWuDi.set_command(command1)
hanWuDi.undo_command()
command1 = WeiQingAttackMainForceCommand()
hanWuDi.set_command(command1)
hanWuDi.issue_command()
print()
print('3.霍去病也隨後請示皇帝,說自己到達了匈奴老窩,於是皇帝頒發了新的命令:霍去病攻打匈奴王庭')
hanWuDi.set_command(command2)
hanWuDi.undo_command()
command2 = HuoQuBingAttackPalaceCommand()
hanWuDi.set_command(command2)
hanWuDi.issue_command()
執行結果:
1.漢武帝發佈命令:衛青攻打匈奴王庭,霍去病攻打匈奴主力。
衛青:我現在去攻打匈奴王庭
霍去病:我現在去攻打匈奴主力
2.衛青中途遇到了匈奴主力,請示皇帝后,皇帝頒發了新的命令:衛青攻打匈奴主力
衛青:我已停止攻打匈奴王庭
衛青:我現在去攻打匈奴主力
3.霍去病也隨後請示皇帝,說自己到達了匈奴老窩,於是皇帝頒發了新的命令:霍去病攻打匈奴王庭
霍去病:我已停止攻打匈奴主力
霍去病:我現在去攻打匈奴王庭