命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
模式动机
在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。
实现
我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。实体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。创建作为调用对象的类 Broker,它接受订单并能下订单。
Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。CommandPatternDemo,我们的演示类使用 Broker类来演示命令模式。
//步骤一 创建一个命令接口 class Order { public: virtual void execute() {} }; //步骤二 创建一个请求类 class Stock { private: string name = "ABC"; int quantity = 10; public: void Buy() { printf("Buy Stock Name = %s, Quantity = %d",name.c_str(),quantity); } void Sell() { printf("Sell Stock Name = %s, Quantity = %d", name.c_str(), quantity); } }; //步骤 3 创建实现了 Order 接口的实体类 class BuyStock : public Order { private: Stock* abcstock; public: BuyStock(Stock* stock) { abcstock = stock; } BuyStock() {} void execute() { abcstock->Buy(); } }; class SellStock :public Order { private: Stock * abcstock; public: SellStock(Stock* stock) { abcstock = stock; } SellStock() {} void execute() { abcstock->Sell(); } }; //步骤 4 创建命令调用类 class Broker { private: list<Order*> orderlist; public: void takeOrder(Order* ord) { orderlist.push_back(ord); } void placeOrders() { list<Order*>::iterator ite = orderlist.begin(); for (; ite != orderlist.end(); ++ite) { (*ite)->execute(); } } }; int main() { Stock stock; BuyStock buy(&stock); SellStock sell(&stock); Broker broker; broker.takeOrder(&buy); broker.takeOrder(&sell); broker.placeOrders(); return 0; }