简介
以請求作為主導角色對封装完成一项操作(如撤销、重做、复制、粘贴等)或在觸发一个事件(如滑鼠單擊、雙擊等)时執行所需行為,简而言之,这意味着创建一个命令类來包含该操作/事件所需的逻辑動作並由請求主導該命令之執行。
- 之後客戶端就可下達請求來調用此命令類以執行。
- 可將调用与执行命令的对象解耦,调用者无需知道命令的任何实现细节。
- 亦可組合命令,如在实现一个多层撤销命令时,此在應用中非常常見。
应用案例:
撤销操作是命令模式的杀手级应用案例,然而命令模式能做的实际上还有很多,如:
- GUI工具列按钮或菜单项:实现圖形介面上工具列按钮或菜单项上的动作,如剪切、复制、 粘贴、重做…等。
- 事务型行为和日志记录:事务型行为和日志记录对于变更记录常保有一份持久化日志,如操作系统可用它从系统崩溃中作恢复、关系型数据库可用它来实现事务、文件系统可用它来实现快照、向导安装程序可用它来恢复取消的安装。
UML图
- 命令Command抽象類:声明接口
- 命令ConcreteCommand具体類:實作接口方法並與接收Receive類作绑定以執行需求之操作。
- 接收Receiver類:負責執行相关需求之業務邏輯的操作。
- 請求Invoker類:此為命令式下執行之主導角色,其須梆定命令ConcreteCommand具体對象以對下達請求來执行相應命令。
示例1:
# -*- coding: utf8 -*-
from abc import ABCMeta,abstractmethod
class Command(metaclass= ABCMeta): #命令抽象类:声明接口
@abstractmethod
def execute(self):
pass
class ConcreteCommand(Command): #命令具体類:實作命令抽象類所声明之接口,並須與接收对象作绑定以可執行其相关需求之業務邏輯操作。
def __init__(self,recv):
self.recv = recv
def execute(self):
self.recv.action()
class Receiver: #接收類:負責執行相关需求之業務邏輯操作
def action(self):
print ("Receiver Action")
class Invoker: #请求類:此為命令模式下執行之主導角色,其須梆定命令ConcreteCommand具体對象以對下達請求來执行相應命令
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()
輸出:
Receiver Action
示例2:
# -*- coding: UTF-8 -*-
from abc import ABCMeta, abstractmethod
class Order(metaclass=ABCMeta): #订单抽象类(*Command)
@abstractmethod
def execute(self):
pass
class BuyStockOrder(Order): #购买股票订单具体類(*ConcreteCommand)
def __init__(self,stock):
self.stock = stock
def execute(self): #實作抽象類定義之接口
self.stock.buy()
class SellStockOrder(Order): #卖股票訂單具体類(*ConcreteCommand)
def __init__(self, stock):
self.stock = stock
def execute(self):
self.stock.sell()
class StockTrade: #股票交易類(*Receiver)
def buy(self):
print ("You will buy stocks")
def sell(self):
print ("You will sell stocks")
class Agent: #代理類(*invoker)
def __init__(self):
self.__orderQueue = []
def placeOrder(self, order):
self.__orderQueue.append(order)
order.execute()
# Client
if __name__ == '__main__':
#Receiver
stock = StockTrade()
#Command
buyStock = BuyStockOrder(stock)
sellStock = SellStockOrder(stock)
# Invoker
agent = Agent()
agent.placeOrder(buyStock)
agent.placeOrder(sellStock)
輸出:
You will buy stocks
You will sell stocks
命令模式的优缺点
1.优点
1.1 将调用操作的类与执行该操作的对象解耦。
1.2 可提供队列型式來创建一系列組合命令
1.3 添加新命令更加容易,且无需更改现有代码
1.4常見於回滚系统之定义,例如在向導示例中我们可以编写一个回滚方法。
2.缺点
2.1 为了实现目标,需要大量的类來进行协作。
2.2 每个单独命令都是一个ConcreteCommand类,从而會因增加需要而实现欲维护的类数量。