设计模式笔记——命令模式

设计模式笔记——命令模式

基本介绍

命令模式是与观察者模式都是行为型设计模式的一种,行为型模式注重于事情的响应性,当客户端触发一个事件之后,与操作相关的参数以对象的形式封装起来,提交给相应的处理对象解析执行,这个封装起来了的对象包含了执行这个操作所需要的全部信息,比如:

  • 方法名称
  • 拥有方法的对象
  • 方法参数的值

比如一个安装向导程序,用户在界面上进行一些列的选项操作之后…,这些选项会封装到一个或多个对象中,提交到一个对象管理器中,一系列配置选项完成之后,点击Install,对象管理器就根据之前传入的参数配置进行程序的安装,分别运行这些对象的execute方法,具体执行程序的安装。

还有示例就是打印机后台处理程序,当选择打印功能之后,在配置打印内容、纸张大小、颜色…等等配置之后,这些配置会以对象的形式存储在Command中,当点击打印是,就会执行Command的execute方法执行打印操作

对于命令模式,其有以下一些术语Client、Receiver、Command、Invoker

  • Command了解Receiver的具体细节,他是直接调用Receiver来执行相关命令的调用者,Command里面封装着执行这条指令或响应所需求的所有信息,在调用Receiver的时候直接提供给Receiver
  • Receiver是具体执行这些功能的类,它具体执行需求,一个Reciver可能执行一种功能,也可能执行很多功能
  • Client针对于不同的响应去负责创建相应的Command对象,并为这个Command设置相应的执行功能的Reciver
  • Invoker能维护这些Command对象,能调用执行这些Command的execute,并且能实现相应的回滚操作(比如shell的上键跳转上一条命令)

其主要意图是:

  • 将请求封装成对象
  • 可用不同的请求对客户进行参数化
  • 允许将请求保存在队列中,实现一些扩展的功能
  • 提供面向对象的回调
  • 根据需要执行的操作对对象进行参数化
  • 将操作添加到队列并在不同地点执行请求
  • 创建一个结构来根据较小操作完成高级操作

示例

比如一个安装程序,用户在操作界面进行相应操作,这些操作被封装成一个对象保存到Wizard中去,当所有配置配置完了,用户点击install,执行execute方法对程序进行安装

# -*- coding=utf-8 -*-

class Wizard(object):

    def __init__(self, src: str, rootdir: str):
        self.choices = []
        self.rootdir = rootdir
        self.src = src

    def preference(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.rootdir)
            else:
                print("No Operation")


if __name__ == "__main__":

    # client code
    wizard = Wizard("python.zip", "/usr/bin/")
    
    # User choose to install Python only
    wizard.preference({"python": True})
    wizard.preference({"Java": False})
    
    # user click install
    wizard.execute()
Copying binaries -- python.zip to /usr/bin/
No Operation

UML图

image-20211124191955496

Command:声明了一个执行操作的接口

ConcreteCommand:将一个Receiver对象和一个操作绑定在一起

Client:创建ConcreteCommand对象并且将其跟对应的Receiver绑定在一起

Invoker:要求改ConcreteCommand执行某个请求

Receiver:知道某个特定的功能如何实现,需要什么

用代码了解就是

# -*- coding=utf-8 -*-

from abc import ABCMeta, abstractmethod

class Command(metaclass=ABCMeta):

    def __init__(self, rece):
        self.rece = rece

    @abstractmethod
    def execute(self):
        pass


class ConcreteCommand(Command):

    def execute(self):
        self.rece.action()


class Receiver(object):

    def action(self):
        print("ConcreteCommand call the real receiver to do this requester")


class Invoker(object):

    def command(self, cmd: Command):
        self.cmd = cmd

    def execute(self):
        self.cmd.execute()


if __name__ == "__main__":

    # client
    receiver = Receiver()
    command = ConcreteCommand(receiver)
    invoker = Invoker()
    invoker.command(command)
    invoker.execute()
ConcreteCommand call the real receiver to do this requester

客户端创建ConcreteCommand并且为这个Command配置对应的Receiver对象,并将其提交到Invoker中,Invoker将command存入其维护的一个command队列中,能够实现调用和回滚等操作

实例

以一个证券交易为例子,用户去买入和卖出股票,他是无法直接去证券交易所的,用户的售卖通过一个代理(Agent),这些需求存储在代理的ToDoList中,当到特定的事件,这个代理会处理这些需求,在证券交易所进行相应的处理

对于用户的命令,它有一个基类Order,里面定义了一个接口execute,在此基础上实现两个子类ButStockOrder用于买入股票和SellStockOrder用于卖出票,这里Order对应Command,实现的子类对应ConcreteCommand

以及具体实现这些操作的类StockTrade,实现具体的响应,对应Receiver,其里面有一个buy方法和sell方法,实现股票的买入和卖出

以及代理类Agent,Agent对应Invoker,其有一个placeOrder用于加入响应,并且执行响应操作的功能

其实现如下

Python实现

# -*- coding=utf-8 -*-

from abc import ABCMeta, abstractmethod
import datetime


class Order(metaclass=ABCMeta):
	"""
	package the user's order into class Order 
	"""
    @abstractmethod
    def execute(self):
        pass


class BuyStockOrder(Order):

    def __init__(self, stoc):
        self.stoc = stoc

    def execute(self):
        date = datetime.date.today()
        self.stoc.buy(date)


class SellStockOrder(Order):

    def __init__(self, stoc):
        self.stoc = stoc

    def execute(self):
        date = datetime.date.today() + datetime.timedelta(days=3)
        self.stoc.sell(date)


class StockTrade(object):

    def buy(self, date: str):
        print(date, ":You buy the stock!")

    def sell(self, date: str):
        print(date, ":You sell the stock!")


class Agent(object):

    def __init__(self):
        self.__orderQueue = []

    def placeOrder(self, order: Order):
        self.__orderQueue.append(order)
        order.execute()


if __name__ == "__main__":

    # client
    stock = StockTrade()
    buyStock = BuyStockOrder(stock)
    sellStock = SellStockOrder(stock)

    # Invoker
    agent = Agent()
    agent.placeOrder(buyStock)
    agent.placeOrder(sellStock)
2021-11-24 :You buy the stock!
2021-11-27 :You sell the stock!

C++实现

#include<iostream>
#include<vector>

using namespace std;

class StockTrade{

public:
    StockTrade() = default;

public:
    inline void buy(){
        cout<<"You will buy the stock!"<<endl;
    }

    inline void sell(){
        cout<<"You will sell the stock!"<<endl;
    }
};

class Order{

public:
    virtual void execute() = 0;
};

class BuyStockOrder: public Order{

public:
    BuyStockOrder(StockTrade trade){
        this->trade = trade;
    }

public:
    void execute() override{
        trade.buy();
    }

private:
    StockTrade trade;
};

class SellStockOrder: public Order{

public:
    SellStockOrder(StockTrade trade){
        this->trade = trade;
    }

public:
    void execute() override{
        trade.sell();
    }

private:
    StockTrade trade;
};

class Agent{

public:
    Agent(){
        cmd_queue = vector<Order*>();
    }

public:
    void placeOrder(Order *order){
        cmd_queue.push_back(order);
        order->execute();
    }

private:
    vector<Order*> cmd_queue;
};

int main(int argc, char *argv[]){
    // Client
    StockTrade stock = StockTrade();
    BuyStockOrder *buyStock = new BuyStockOrder(stock);
    SellStockOrder *sellStock = new SellStockOrder(stock);

    // Invoker
    Agent agent = Agent();
    agent.placeOrder(buyStock);
    agent.placeOrder(sellStock);
}
You will buy the stock!
You will sell the stock!

优缺点

优点:

  • 将调用操作的类于知道如何执行该操作的对象进行解耦
  • 提供队列系统之后,可以执行一系列命令
  • 添加新命令容易,并且无需更改代码
  • 可以实现类似于shell的回滚操作

缺点:

  • 为了实现目标,需要大量的类和对象进行协作。
  • 每一个单独的命令都是一个ConcreteCommand,需要维护和实现的类的数量很多
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值