命令设计模式简介
行为模式侧重于对象的响应性,它利用对象之间的交互实现更强大的功能。命令模式也是一种行为设计模式,其中对象用于封装在完成一项操作时或在触发一个事件时所需的全部信息。
命令模式通常使用以下术语: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类,从而增加了需要实现和维护的类的数量