问题聚焦:
感觉后面的一些模式都比较抽象,每个模式都尽量写一个demo辅助理解。
命令行模式主要是将请求本身封装为对象,从而使你可用不同的请求参数化客户类。
解耦了调用操作的对象和具有执行该操作所需信息的那个对象
结构:
Command:
定义命令的接口,声明执行的方法。
ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
定义命令的接口,声明执行的方法。
ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
关键:
- 抽象的Command类,定义了一个执行操作的接口,其最简单的形式是一个抽象的Execute操作
- 具体的Command子类将接收者作为其一个实例变量,并实现Execute操作,Execute操作调用接受者的具体的操作
- 当需要执行一系列命令时,实现一个具体的Command子类MarcoCommand,执行一个命令序列
- 效果是解耦了调用操作的对象和具有执行该操作所需信息的那个对象
实例:
场景:
- 手机可以有解锁,点击屏幕,锁屏等操作
- 这里,手机是激活命令执行的Invoker
- 手机的使用者是请求发送者
- 手机内部的元器件(处理器,声卡)是请求的最终执行者
解耦:使用者只是按下了电源键,进行解锁,并不知道是手机里的哪个元件实现的了解锁的,这就把使用者和具体的元件解耦,让使用者只和电源键这个接口进行交互
实现:
相关类的声明:
#ifndef COMMANDHD #define COMMANDHD #include <iostream> /* * reciever, 命令实际接收执行者,包括处理器,声卡 */ class Processor { public: Processor(); void unlockScreen(); void startApp(); void lockScreen(); }; class SoundCard { public: SoundCard(); void incraseSound(); void decreaseSound(); }; /* * 命令基类 */ class Command { public: virtual ~Command() {}; virtual void execute() = 0; protected: Command() {}; }; /* 具体命令 */ class LockScreenCommand : public Command { public: LockScreenCommand(Processor* processor); virtual void execute(); private: Processor* _processor; }; class IncSoundCmd : public Command { public: IncSoundCmd(SoundCard* soundcard); virtual void execute(); private: SoundCard* soundcard; }; // ...... /* * 手机,Invoker,激活命令执行,使用者与它进行交互 */ class Phone { public: /* * 设置手机按钮的接口功能 */ void setCommand( Command* command ); /* * 执行命令(转发至具体的元器件) */ void runCommand(); private: Command * _command; }; #endif
使用者:
这里的User充当了组装者(为手机的接口分配智能)和使用者的双重角色。
因为按钮的一些功能的实现和绑定应该在组装手机的时候实现
那样的话,需要参数化runCommand,维护一个功能映射字典
为了实现方便,在用户使用的时候才绑定对应的命令
那样的话,需要参数化runCommand,维护一个功能映射字典
为了实现方便,在用户使用的时候才绑定对应的命令
#include "command.h" class User { public: User(); void buyPhone(); void lockScreen(); void unlockScreen(); void startApp(); void incSound(); void decSound(); private: Phone* _myphone; Processor* _processor; SoundCard* _soundCard; };
测试:
#include "user.h" int main() { User* user = new User(); user->unlockScreen(); user->startApp(); user->incSound(); user->decSound(); user->lockScreen(); system("Pause"); }运行截图:
编译环境:VS2010
参考资料:
《设计模式:可复用面向对象软件的基础》