设计模式之责任链模式(二): 实现方式

C++设计模式专栏:http://t.csdnimg.cn/8Ulj3

相关文章系列

设计模式之责任链模式(一)-CSDN博客

目录

1.引言

2.实现方式1

3.实现方式2

4.总结        


1.引言

        责任链设计模式(Chain of Responsibiliy DesignPattern)简称职责链模式。在GOF的《设计模式:可复用面向对象软件的基础》中,它是这样定义的:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求;将这些接收对象串成一条链,并沿者这条链传递这个请求,直到链上的某个接收对象能够处理它为止(Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it )。

        在职责链模式中,多个处理器(也就是定义中所说的“接收对象”)依次处理同一个请求。一个请求首先经过A处理器处理,然后,这个请求被传递给B处理器,B处理器处理完后再将其传递给C处理器,以此类推,形成一个链条。因为链条上的每个处理器各自承担各自职责,所以称为职责链模式。

        职责链模式有多种实现方式,这里介绍两种常用的。

2.实现方式1

        实现方式的代码如下所示。其中,Handler类是所有处理器类的抽象父类,handle()是抽象方法。每个具体的处理器类(HandlerA、HandlerB)的handle()函数的代码结构类似,如果某个处理器能够处理该请求,就不继续往下传递;如果它不能处理,则交由后面的处理器处理(也就是调用successor.handle())。HandlerChain类表示处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录链尾是为了方便添加处理器。

#pragma once
#include <memory>
#include <vector>class IHandler
{
protected:IHandler* m_successor;
public:void setSuccessor(IHandler* successor) {m_successor = successor;}virtual void handle() = 0;
};class HandlerA : public IHandler
{
public://...//@overridevoid handle() override {bool bHandle = false;//...if (!bHandle && m_successor) {m_successor->handle();}//...}
};class HandlerB : public IHandler
{
public://...//@overridevoid handle() override {bool bHandle = false;//...if (!bHandle && m_successor) {m_successor->handle();}//...}
};class HandlerChain {
private:IHandler* head = nullptr;IHandler* tail = nullptr;
public:void addHandler(IHandler* handler) {handler->setSuccessor(nullptr);if (head == nullptr) {head = handler;tail = handler;return;}tail->setSuccessor(handler);tail = handler;}void handle() {if (head != nullptr) {head->handle();}}
};//使用举例
int main() {std::unique_ptr<IHandler> pHandleA(new HandlerA());std::unique_ptr<IHandler> pHandleB(new HandlerB());HandlerChain chain;chain.addHandler(pHandleA.get());chain.addHandler(pHandleB.get());chain.handle();return 1;
}

        实际上,上面的代码实现不够优雅,因为处理器类的handle()函数不仅包含自己的业务逻辑。还包含对下一个处理器的调用(对应代码中的successor.handle())。如果一个不熟悉这种代码结构的程序员想要在其中添加新的处理器类,那么很有可能忘记在handle()函数中调用successor.handle(),这就会导致代码出现bug。

设计模式之模板方法模式-CSDN博客

        针对这个问题,我们对代码进行重构,利用模版方法模式,将调用successor.handle()的逻辑从处理器中剥离出来,放到抽象父类中。这样,处理器类只需要实现自己的业务逻辑。重构之后的代码如下所示:

class IHandler
{
protected:IHandler* m_successor;
public:void setSuccessor(IHandler* successor) {m_successor = successor;}void handle() {bool bHandled = doHandle();if (!bHandled && m_successor) {m_successor->handle();}}
protected:virtual bool doHandle() = 0;
};class HandlerA : public IHandler
{
protected://...//@overridebool doHandle() override {bool bHandle = false;//...return bHandle;}
};class HandlerB : public IHandler
{
protected://...//@overridebool doHandle() override {bool bHandle = false;//...return bHandle;}
};class HandlerChain {
private:IHandler* head = nullptr;IHandler* tail = nullptr;
public:void addHandler(IHandler* handler) {handler->setSuccessor(nullptr);if (head == nullptr) {head = handler;tail = handler;return;}tail->setSuccessor(handler);tail = handler;}void handle() {if (head != nullptr) {head->handle();}}
};int  main() {std::unique_ptr<IHandler> pHandleA(new HandlerA());std::unique_ptr<IHandler> pHandleB(new HandlerB());HandlerChain chain;chain.addHandler(pHandleA.get());chain.addHandler(pHandleB.get());chain.handle();return 1;
}

3.实现方式2

        实现代码如下所示,这种实现方式更加简单,其中HandlerChain 类用数组而非链表来保存所有处理器类,并且在HandlerChain类的handle()函数中,依次调用每个处理器类的 handle()函数。

class IHandler
{
public:virtual bool handle() = 0;
};class HandlerA : public IHandler
{
public://...//@overridebool handle() override {bool bHandle = false;//...return bHandle;}
};class HandlerB : public IHandler
{
public://...//@overridebool handle() override {bool bHandle = false;//...return bHandle;}
};class HandlerChain {
private:std::vector<IHandler*> m_vecHandler;
public:void addHandler(IHandler* handler) {m_vecHandler.push_back(handler);}void handle() {for (auto& it : m_vecHandler) {if (it->handle()) {break;}}}
};int main() {std::unique_ptr<IHandler> pHandleA(new HandlerA());std::unique_ptr<IHandler> pHandleB(new HandlerB());HandlerChain chain;chain.addHandler(pHandleA.get());chain.addHandler(pHandleB.get());chain.handle();return 1;
}

        在GoF合著的《设计模式:可复用面向对象软件的基础》给出的职责链模式的定义中。如果处理器链上的某个处理器能够处理这个请求,就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有处理器都处理一遍,不存在中途终止的情况。这种变体也有两种实现方式: 用链表存储处理器类和用数组存储处理器类,与上面两种实现方式类似稍加修改即可。这里只给出用链表存储处理器类的实现方式,代码如下所示。对于用数组存储处理器类的实现方式,读者可对照上面的实现自行修改。

class IHandler
{
protected:IHandler* m_successor;
public:void setSuccessor(IHandler* successor) {m_successor = successor;}void handle() {doHandle();if (m_successor) {m_successor->handle();}}
protected:virtual void doHandle() = 0;
};class HandlerA : public IHandler
{
protected://...//...//@overridevoid doHandle() override {//...}
};class HandlerB : public IHandler
{
protected://...//@overridevoid doHandle() override {//...}
};class HandlerChain {
private:IHandler* head = nullptr;IHandler* tail = nullptr;
public:void addHandler(IHandler* handler) {handler->setSuccessor(nullptr);if (head == nullptr) {head = handler;tail = handler;return;}tail->setSuccessor(handler);tail = handler;}void handle() {if (head != nullptr) {head->handle();}}
};int main() {std::unique_ptr<IHandler> pHandleA(new HandlerA());std::unique_ptr<IHandler> pHandleB(new HandlerB());HandlerChain chain;chain.addHandler(pHandleA.get());chain.addHandler(pHandleB.get());chain.handle();return 1;
}

4.总结        

        尽管我们给出了典型的职责链模式的代码实现,但在实际的开发中,我们还是要具体问题具体对待,因为职责链模式的代码实现会根据需求的不同而有所变化。实际上,这一点对于有设计模式都适用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/3686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第12章 最佳的UI体验——Material Design实战

第12章 最佳的UI体验——Material Design实战 其实长久以来&#xff0c;大多数人都认为Android系统的UI并不算美观&#xff0c;至少没有iOS系统的美观。以至于很多IT公司在进行应用界面设计的时候&#xff0c;为了保证双平台的统一性&#xff0c;强制要求Android端的界面风格必…

HarmonyOS开发案例:【 自定义弹窗】

介绍 基于ArkTS的声明式开发范式实现了三种不同的弹窗&#xff0c;第一种直接使用公共组件&#xff0c;后两种使用CustomDialogController实现自定义弹窗&#xff0c;效果如图所示&#xff1a; 相关概念 [AlertDialog]&#xff1a;警告弹窗&#xff0c;可设置文本内容和响应回…

了解HTTP代理服务器:优势、分类及应用实践

在我们日常的网络使用中&#xff0c;我们经常听到HTTP代理服务器这个术语。那么&#xff0c;HTTP代理服务器到底是什么&#xff1f;它有什么优势和分类&#xff1f;又如何应用于实践中呢&#xff1f;让我们一起来了解一下。 HTTP代理服务器是一种位于客户端和服务器之间的中间…

图像处理基础知识

图像处理基础知识 图像 1、模拟图像 模拟图像&#xff0c;又称连续图像&#xff0c;是指在二维坐标系中连续变化的图像&#xff0c;即图像的像点是无限稠密的&#xff0c;同时具有灰度值&#xff08;即图像从暗到亮的变化值&#xff09;。 2、数字图像 数字图像&#xff0…

Android13锁屏或灭屏状态下,快速按两次音量下键实现打开闪光灯功能

实现思路&#xff1a; 1、发送广播 WindowManagerService循环读取下面按键消息并分发给窗口&#xff0c;在消息分发前会在PhoneWindowManager.interceptKeyBeforeQueueing方法中进行消息的过滤。因此该实现方式为在消息分发前的interceptKeyBeforeQueueing方法中监听当前按键为…

Python基础知识—运算符和if语句(二)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》 《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 1.输入和输出函数1.1输出函数1.2输入函数 2.常见运算符2.1赋值运算符2.2比较运算符2.3逻辑运算符2.4and逻辑与2.5or逻辑或2.6not逻…

ceph介绍

一、前言 Ceph 是一个完全分布式的系统&#xff0c;它将数据分布在整个集群中的多个节点上&#xff0c;以实现高可用性和容错性&#xff0c;ceph支持对象存储、块存储、文件存储所以被称为统一存储&#xff0c;ceph的架构由以下组件组成:mon、mgr、osd、mds、cephfs、rgw&#…

深度学习Day-14:RNN实现心脏病预测

&#x1f368; 本文为&#xff1a;[&#x1f517;365天深度学习训练营] 中的学习记录博客 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制] 要求&#xff1a; 本地读取并加载数据&#xff1b;了解循环神经网络RNN的构建过程&#xff1b;测试集accuracy达到87%…

自己搭建的大疆无人机RTMP流媒体服务延迟太大

流程&#xff1a;无人机摄像头->图传->遥控器->流媒体服务器->取流播放&#xff0c;延迟有10秒来的&#xff0c;大家有没有什么好的方案。

C# 结合JavaScript实现手写板签名并上传到服务器

应用场景 我们最近开发了一款笔迹测试功能的程序&#xff08;测试版&#xff09;&#xff0c;用户在手写板上手写签名&#xff0c;提交后即可测试出被测试者的心理素质评价分析。类似功能的场景还比如&#xff0c;在银行柜台办理业务&#xff0c;期间可能需要您使用手写设备进…

2023最新!nginx安装配置保姆级教程

2023最新!nginx安装配置保姆级教程 这篇文章了参考了这位的教程:https://blog.csdn.net/qq_36838700/article/details/129971765 导航 文章目录 2023最新!nginx安装配置保姆级教程一、nginx下载二、编译安装nginx安装pcre安装openssl、zlib、gcc依赖安装nginx 二、拓展 一、n…

低空经济+飞行汽车:载人无人机技术详解

低空经济与飞行汽车是近年来备受关注的话题。随着科技的不断进步&#xff0c;尤其是无人机技术的快速发展&#xff0c;飞行汽车已经从科幻概念逐渐变为现实。以下是对低空经济与飞行汽车&#xff0c;特别是载人无人机技术的详解&#xff1a; 1. 低空经济&#xff1a; 定义&…

isListEqual方法比较

这个方法有改进空间吗&#xff1f; private static boolean isListEqual(List<String> l0, List<String> l1) {if (l0 null && l1 null)return true;if (l0 l1)return true;if (l0 null || l1 null)return false;if (l0.size() ! l1.size())return f…

ADB 命令获取Android 设备的屏幕分辨率和屏幕像素密度

1. 获取屏幕分辨率和像素密度 获取 Android 设备屏幕分辨率&#xff1a; adb shell wm size Physical size: 1440x3120 获取android设备屏幕密度(DPI)&#xff1a; adb shell wm density Physical density: 560 打印屏幕相关的详细信息&#xff1a; adb shell dumpsys wi…

javaEE--多线程学习-进程调度

进程调度不明白&#xff1f;看这一篇文章就够了&#xff0c;逻辑衔接严密&#xff0c;文末附有关键面试题&#xff0c;一个海后的小故事让你瞬间明白这里面的弯弯绕绕&#xff01; 目录 1.什么是进程&#xff1f; 2.进程控制块&#xff08;PCB&#xff09; 2.1 一个PCB就是一…

顺序表 (C语言版)

顺序存储&#xff1a; 把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中&#xff0c;元素之间的关系由存储单元的邻接关系来体现。 顺序表的特点&#xff1a; 能在O(1)的时间内找到第i个元素存储密度高拓展容量不方便插入&#xff0c;删除操作不方便 C语言中可使用&am…

已解决java.lang.IllegalThreadStateException: 非法线程状态异常的正确解决方法,亲测有效!!!

已解决java.lang.IllegalThreadStateException: 非法线程状态异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 场景描述 报错原因 解决思路 解决方法 检查线程状态 正确管理线程生命周期 异常处理 总结 博主v&#xff1a…

JavaEE >> Spring Boot(1)

Spring Boot 前面已经介绍了 Spring &#xff0c;是为了简化 Java 程序开发的&#xff0c;而在前面创建的过程中就会发现其实 Spring 还是有点复杂&#xff0c;此时 Spring Boot 就诞生了&#xff0c; Spring Boot 是为了简化 Spring 程序开发的。 Spring Boot 即 Spring 脚手…

history日志发送到远程日志服务器

主要目标是设置history信息包含谁、源IP、在哪个目录下、做了什么工作&#xff0c;并实时将日志发送到日志审计服务。 &#xff08;一&#xff09;基础知识 1.logger 是一个shell接口&#xff0c;可以通过该接口使用rsyslog的日志模块 2./etc/profile.d/history.sh比配置/etc…

Android某钉数据库的解密分析

声明 1 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 目的 1 解密app数据库&#xff0c;用数据库软件打开查看信息内容 入手…