23种设计模式之C++实践
- 3. 设计模式
- (三)行为型模式
- 14. 职责链模式——请求的链式处理
- 职责链模式总结
- 15. 命令模式:请求发送者与接收者解耦
- 命令模式总结
- 16. 解释器模式——自定义语言的实现
- 解释器模式总结
- 17. 迭代器模式——遍历聚合对象中的元素
- 迭代器模式总结
- 18. 中介者模式——协调多个对象之间的交互
- 中介者模式总结
- 19. 备忘录模式——撤销功能的实现
- 备忘录模式总结
- 20. 观察者模式——对象间的联动
- 观察者模式总结
- 21. 状态模式——对象状态及其转换
- 状态模式总结
- 22. 策略模式——算法的封装和切换
- 策略模式总结
- 23. 模板方法模式——定义算法的框架
- 模板方法模式总结
- 24. 访问者模式——操作复杂对象结构
- 访问者模式总结
3. 设计模式
(三)行为型模式
14. 职责链模式——请求的链式处理
-
职责链模式(Chain of Responsibility Pattern):避免将请求接收者与发送者耦合在一起,让多个对象都有机会接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,知道有对象处理它为止。
-
要点
- 职责链模式并不创建职责链,职责链的创建工作通常是由客户端完成。
-
结构图
-
适用场景示例
采购单的分级审批:不同级别的人员可以审批不同金额的采购单。
-
代码示例
// Approver.h /*** @brief 审批者接口**/ class Approver {protected:Approver* successor;std::string name;public:Approver(std::string name) : name(name) {}void setSuccessor(Approver* successor) {this->successor = successor;return;}virtual void processRequest(PurchaseRequest*) = 0; };class Director : public Approver {public:Director(std::string name) : Approver(name) {}public:void processRequest(PurchaseRequest* request) override {if (request->getAmount() < 5000) {printf("主任:%s 审批采购单:%d,金额:%f元,采购目的:%s。\n",name.c_str(), request->getNumber(), request->getAmount(),request->getPurpose().c_str());printf("审批通过!\n");} else {printf("%s审批通过,", name.c_str());printf("进入下一层审批\n");this->successor->processRequest(request);}return;} };class VicePresident : public Approver {public:VicePresident(std::string name) : Approver(name) {}public:void processRequest(PurchaseRequest* request) override {if (request->getAmount() < 10000) {printf("副董事长:%s 审批采购单:%d,金额:%f元,采购目的:%s。\n",name.c_str(), request->getNumber(), request->getAmount(),request->getPurpose().c_str());printf("审批通过!\n");} else {printf("%s审批通过,", name.c_str());printf("进入下一层审批\n");this->successor->processRequest(request);}return;} };class President : public Approver {public:President(std::string name) : Approver(name) {}public:void processRequest(PurchaseRequest* request) override {if (request->getAmount() < 200000) {printf("董事长:%s 审批采购单:%d,金额:%f元,采购目的:%s。\n",name.c_str(), request->getNumber(), request->getAmount(),request->getPurpose().c_str());printf("审批通过!\n");} else {printf("%s审批通过,", name.c_str());printf("进入下一层审批\n");this->successor->processRequest(request);}return;} };class Congress : public Approver {public:Congress(std::string name) : Approver(name) {}public:void processRequest(PurchaseRequest* request) override {if (request->getAmount() < 1000000) {printf("董事会:审批采购单:%d,金额:%f元,采购目的:%s。\n",request->getNumber(), request->getAmount(),request->getPurpose().c_str());printf("审批通过!\n");} else {printf("董事会审批不通过!\n");}return;} };// PurchaseRequest.h class PurchaseRequest {private:double amount;int number;std::string purpose;public:PurchaseRequest(double amount, int number, std::string purpose): amount(amount), number(number), purpose(purpose) {}void setAmount(double amount) {this->amount = amount;return;}void setNumber(double number) {this->number = number;return;}void setPurpose(std::string purpose) {this->purpose = purpose;return;}double getAmount() { return this->amount; }int getNumber() { return this->number; }std::string getPurpose() { return this->purpose; } };
-
代码测试
-
测试代码
int main(int argc, char** argv) {printf("I'm Chain Of Responsibility Pattern!\n");// begin testApprover *num1, *num2, *num3, *num4;num1 = new Director("季");num2 = new VicePresident("叔");num3 = new President("仲");num4 = new Congress("伯");num1->setSuccessor(num2);num2->setSuccessor(num3);num3->setSuccessor(num4);PurchaseRequest* request = new PurchaseRequest(500, 10001, "差旅报销");num1->processRequest(request);PurchaseRequest* request2 = new PurchaseRequest(5000, 10002, "差旅报销");num1->processRequest(request2);PurchaseRequest* request3 = new PurchaseRequest(50000, 10003, "差旅报销");num1->processRequest(request3);PurchaseRequest* request4 = new PurchaseRequest(500000, 10004, "差旅报销");num1->processRequest(request4);PurchaseRequest* request5 = new PurchaseRequest(5000000, 10005, "差旅报销");num1->processRequest(request5);// end testreturn 0; }
-
输出
I’m Chain Of Responsibility Pattern!
主任:季 审批采购单:10001,金额:500.000000元,采购目的:差旅报销。
审批通过!
季审批通过,进入下一层审批
副董事长:叔 审批采购单:10002,金额:5000.000000元,采购目的:差旅报销。
审批通过!
季审批通过,进入下一层审批
叔审批通过,进入下一层审批
董事长:仲 审批采购单:10003,金额:50000.000000元,采购目的:差旅报销。
审批通过!
季审批通过,进入下一层审批
叔审批通过,进入下一层审批
仲审批通过,进入下一层审批
董事会:审批采购单:10004,金额:500000.000000元,采购目的:差旅报销。
审批通过!
季审批通过,进入下一层审批
叔审批通过,进入下一层审批
仲审批通过,进入下一层审批
董事会审批不通过!
-
职责链模式总结
- 优点
- 使得一个对象无须知道其他哪一个对象处理其请求。
- 请求处理对象只需维持一个指向其后继者的引用,可简化对象的相互连接。
- 给对象分配职责时更灵活
- 在客户端增加一个新的具体请求处理者时无需修改原有代码,只需要在客户端重建链即可。
- 缺点
- 请求可能因职责链没有被正确分配而得不到处理
- 职责链过长时,影响系统性能。
- 可能造成死循环
- 适用场景
- 有多个对象处理同一个请求,具体哪个对象处理该请求待运行时再确定。
- 在不明确指定接收者的情况下,向多个对象种的一个提交一个请求。
- 可动态指定一组对象处理请求。
15. 命令模式:请求发送者与接收者解耦
-
命令模式(Command Pattern):将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
-
要点
- 引入抽象命令类,对请求进行封装,将发出命令的责任与执行命令的责任分割开。
-
结构图
-
适用场景示例
自定义功能键
-
代码示例
// Command.h /*** @brief 抽象命令类**/ class Command {public:virtual void execute() = 0; };/*** @brief 帮助命令类:具体命令类**/ class HelpCommand : public Command {private:HelpHandler* helpHandler;public:HelpCommand() { helpHandler = new HelpHandler(); }public:void execute() override {helpHandler->display();return;} };/*** @brief 最小化命令类:具体命令类**/ class MinimizeCommand : public Command {private:WindowHandler* helpHandler;public:MinimizeCommand() { helpHandler = new WindowHandler(); }public:void execute() override {helpHandler->minimize();return;} };// FunctionButton.h /*** @brief 功能键类:请求发送者**/ class FunctionButton {private:std::string name;Command* command;public:FunctionButton(std::string name) : name(name) {}std::string getName() { return name; }void setCommand(Command* command) {this->command = command;return;}void onClick() {printf("点击功能键\n");command->execute();return;} };class FBSettingWindow {private:std::string title;std::vector<FunctionButton*> functionButtons;public:FBSettingWindow(std::string title) { this->title = title; }public:void setTitle(std::string title) {this->title = title;return;}std::string getTitle() { return this->title; }void addFunctionButton(FunctionButton* fb) {functionButtons.push_back(fb);return;}void removeFunctionButton(FunctionButton* fb) {auto begin = functionButtons.begin();auto end = functionButtons.end();while (begin != end) {if (*begin == fb) {functionButtons.erase(begin);break;}begin++;}return;}void display() {printf("显示窗口:%s\n", this->title.c_str());printf("显示功能键:");for (auto fb : functionButtons) {printf("%s ", fb->getName().c_str());}printf("\n");return;} };// Handler.h /*** @brief 帮助文档处理类:请求接收者**/ class HelpHandler {public:void display() {printf("显示帮助文档\n");return;} };/*** @brief 窗口处理类:请求接收者**/ class WindowHandler {public:void minimize() {printf("将窗口最小化至托盘\n");return;} };
-
代码测试
-
测试代码
int main(int argc, char** argv) {printf("I'm Command Pattern!\n");// begin testFBSettingWindow* fbsw = new FBSettingWindow("功能键设置");FunctionButton *fb1, *fb2;fb1 = new FunctionButton("功能键1");fb2 = new FunctionButton("功能键2");Command *command1, *command2;command1 = new HelpCommand();command2 = new MinimizeCommand();fb1->setCommand(command1);fb2->setCommand(command2);fbsw->addFunctionButton(fb1);fbsw->addFunctionButton(fb2);fbsw->display();fb1->onClick();fb2->onClick();// end testreturn 0; }
-
输出
I’m Command Pattern!
显示窗口:功能键设置
显示功能键:功能键1 功能键2
点击功能键
显示帮助文档
点击功能键
将窗口最小化至托盘
-
命令模式总结
- 优点
- 降低系统的耦合度。
- 增加新的命令很容易
- 可以比较容易地设计一个命令队列。
- 可使用命令队列实现”撤销请求“和”回复请求“。
- 缺点
- 可能导致某些系统中有过多的具体命令类。
- 适用场景
- 系统需要将请求调用者与请求接收者解耦。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销操作和恢复操作。
16. 解释器模式——自定义语言的实现
-
解释器模式(Interpreter Pattern