命令模式

目录

1 命令模式

命令模式将”请求”封装成对象(指命令对象,能把方法调用封装起来),以便使用不同的请求、队列或者日志来参数化其他对象(指调用者对象)。命令模式也支持可撤销的操作。

在这里插入图片描述

  • 一个命令对象Command需要绑定一个命令接收者Receiver,将接收者接收者的具体动作封装进来,只暴露出一个execute()方法,当此方法被调用时,就会执行接收者的动作。这样,当调用者对象调用命令对象的execute()方法时,不需要知道是哪个接收者接收到了请求命令也不需要知道接收者执行了哪些动作
  • 通过一个抽象基类的命令接口类,可以扩展出许多具体的命令类,这样就只需要使用接口类对象来参数化调用者对象即可。调用者对象不需要知道具体的命令,只知道他是一个命令即可
  • 可以通过命令模式来实现“队列、日志和支持撤销操作”
    在安装向导、订单系统、遥控控制系统、日程安排、工作队列等诸多现实生活场景中有应用。

2 命令模式的UML类图

在这里插入图片描述

  • Client: 客户端类,创建一个具体的命令对象ConcreteCommand和接收者对象Receiver,并将接收者对象绑定到具体的命令对象中。
  • Receiver: 接收者类,接收者具有执行请求命令的具体方法action()
  • Command: 命令对象的抽象基类,所有的具体命令对象都需要实现此接口,拥有一个execute()方法,调用此方法就可以让接收者进行相关的动作,调用undo()方法可以让接收者进行撤销动作。
  • ConcreteCommand: 具体的命令对象类,实现了Command接口。与接收者绑定起来,调用者调用命令对象的execute()方法就能发出请求命令,然后由命令接收者Receiver接收命令执行相关的动作action()
  • Invoker: 调用者类,传入一个具体的命令对象参数到方法setCommand()中,并在某个时间点调用命令对象的execute()方法

使用步骤:

  • 客户端实例化一个接收者对象receiver一个具体的命令对象command将receiver绑定到command中
  • 实例化一个调用者invoker,并在某个时间点使用一个命令对象传入到setCommand(command)方法中,然后调用命令对象command的execute()方法发出请求命令
  • 在命令对象的execute()方法中,调用与其绑定的接收者的action()方法,执行命令

优势

  • 命令模式将发出请求的调用者对象执行请求的接收者对象解耦`。
  • 解耦的两个对象通过命令对象沟通命令对象封装了接收者的一个或多个动作
  • 调用者调用命令对象的execute()方法发出请求,这使得接收者的动作被调用。
  • 命令对象可以支持撤销,做法是实现一个 undo()方法来回到execute()被执行前的状态
  • 宏命令使用一系列命令对象初始化,然后调用多个命令

3 观察者的一个例子:遥控家电

遥控器有7个插槽,每个插槽对应两个按钮,每个按钮对应到一个命令,这样遥控器就充当了调用者的身份。当按下按钮时,相应命令对象的execute()方法被调用,与其绑定的接收者(例如“电灯”、“天花板电扇”、“音响”)的动作就会被调用。还有一个撤销按钮,当按下时调用命令对象的undo()方法,接收者执行相关的动作。
在这里插入图片描述

3.1 基本功能实现在这里插入图片描述

3.2 撤销按钮功能实现

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 宏命令功能实现

创建一个命令对象,当调用此命令对象的execute()方法后,会执行一系列命令。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4 队列请求和日志请求

4.1 队列请求

如果有一个工作队列:在一端添加命令,在另一端则是线程。线程进行下面的动作:从工作队列中选择一个命令,然后调用execute()方法,等待调用完成后,将此命令对其,再取出下一个命令。两个相邻的命令之间无需有任何关系。前一个命令可以是读取网络数据,下一个命令可以是处理财务运算。

4.2 日志请求

某些应用需要将所有动作记录在日志中。当系统死机时,重新调用这些动作恢复到之前的状态。只需要在命令中新增两个方法store()和load()即可完成。

5 命令模式的一个Python实现例子

5.1 例子解释

假如你是证券交易所的客户,会创建买入股票和卖出股票的订单(即Command)。通常情况下,你通过代理或经纪人(即Invoker)向证券交易所(即Receiver)沟通,而不是直接到证券交易所执行交易。代理负责将你的请求提交给证券交易所,完成股票买入或卖出请求。

5.2 UML类图

在这里插入图片描述

5.3 代码实现

  • 接收者类StockTrade
    • 定义了具体的动作buy()和sell(),由具体命令对象的execute()调用此方法,然后执行具体动作
class StockTrade:
    '''
    Receiver接受者,是一个知道如何做必要的工作的类
    '''
    def buy(self):
        print("You will buy stocks.")
        
    def sell(self):
        print("You will sell stocks.")
  • 命令接口类Order
    • 抽象基类,具有一个execute()方法

from abc import ABCMeta, abstractmethod
class Order(metaclass=ABCMeta):
    '''
    命令Command的抽象基类,即为具体的命令类提供了一个接口
    '''
    @abstractmethod
    def execute(self):
        '''通过调用命令对象的execute()方法,可以让接收者进行相应的工作'''
        pass```
  • 具体的命令对象类BuyStockOrder、SellStockOrder
    • 首先构造函数__init__(stock)使用一个接收者对象stock初始化属性stock
    • 实现的execute()方法调用stock的buy()或sell()方法
    
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()
    
    
  • 调用者类Agent
    • 首先构造函数__init__()初始化__orderQueue属性为一个空列表
    • 传入一个具体命令对象给placeOrder(order)方法,并在某一时刻调用此方法发出请求然后执行命令对象的execute()方法在execute()方法中,执行接收者的动作完成请求
class Agent:
    '''
    Invoker调用者
    '''
    def __init__(self):
        self.__orderQueue = []
        
    
    def placeOrder(self, order):
        '''调用者拥有一个命令对象列表,在某个时刻调通过此方法调用命令对象的execute()方法,将请求付诸实行'''
        self.__orderQueue.append(order)
        order.execute()
        
  • 客户端
    • 客户端实例化一个接收者对象stock具体的命令对象buyStock、sellStock将stock绑定到具体命令中
    • 实例化一个调用者agent,并在某个时间点将一个命令对象传入到placeOrder(order)方法中,然后调用命令对象的execute()方法发出请求命令
    • 在命令对象的execute()方法中,调用与其绑定的接收者的buy()方法或sell()方法,执行命令
if __name__ == '__main__':
    # Client
    stock = StockTrade() # 客户先实例化一个接收者对象
    buyStock = BuyStockOrder(stock) # 然后将接收者对象与具体的命令对象绑定起来
    sellStock = SellStockOrder(stock) # 将接收者对象与具体的命令对象绑定起来
    
    # Invoker
    agent = Agent() # 实例化一个调用者对象
    agent.placeOrder(buyStock) # 将命令对象与调用者绑定起来,调用者`发出命令执行请求`
    agent.placeOrder(sellStock) # 将命令对象与调用者绑定起来,`发出命令执行请求`

5.4 输出结果

在这里插入图片描述
github地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值