23种设计模式之C++实践(三)
2023-12-14 09:30:31
23种设计模式之C++实践
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 test Approver *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 test return 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 test FBSettingWindow* 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 test return 0; }
-
输出
I’m Command Pattern!
显示窗口:功能键设置
显示功能键:功能键1 功能键2
点击功能键
显示帮助文档
点击功能键
将窗口最小化至托盘
-
命令模式总结
- 优点
- 降低系统的耦合度。
- 增加新的命令很容易
- 可以比较容易地设计一个命令队列。
- 可使用命令队列实现”撤销请求“和”回复请求“。
- 缺点
- 可能导致某些系统中有过多的具体命令类。
- 适用场景
- 系统需要将请求调用者与请求接收者解耦。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销操作和恢复操作。
16. 解释器模式——自定义语言的实现
-
解释器模式(Interpreter Pattern
文章来源:https://blog.csdn.net/weixin_50749380/article/details/134762039
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!