设计模式第六讲:责任链模式和迭代器模式详解
一. 责任链模式
1. 背景
在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。
2. 定义和特点
(1). 定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
PS:责任链模式也叫职责链模式。在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
(2). 优点:
A. 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
B. 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
C. 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
D. 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
E. 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
(3). 缺点:
A. 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
B. 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
C. 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
3. 具体实现
(1). 模式结构
A. 抽象处理者:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
B. 具体处理者:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
C. 客户端调用:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
结构图如下:
(2). 使用场景
员工请假,不同的天数需要被不同级别的领导批准,这个时候可以采用责任链模式。每个领导都是一个具体的请假处理者,同时提炼出来一个抽象处理者,包括:请假处理方法和下一个节点,最后由客户端建立责任链,并将请求传递进去。
更多C++后台开发技术点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux内核,TCP/IP,协程,DPDK多个高级知识点。
C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址
【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取
(3). 代码实操
请假请求类:
/// <summary>/// 请假请求类/// </summary>public class LeaveRequest{/// <summary>/// 姓名/// </summary>public string name { get; set; }/// <summary>/// 请假天数/// </summary>public int leaveDays { get; set; }}
抽象处理者和具体处理者:
/// <summary>/// 抽象处理者角色/// </summary>public abstract class AbstractHandler{/// <summary>/// 代表责任链中的下一个角色/// </summary>public AbstractHandler NextHandler { get; set; }/// <summary>/// 处理请假请求/// </summary>public abstract void HandleRequest(LeaveRequest request);}/// <summary>/// 直接领导(一级领导)/// </summary>public class LeaderHandler1 : AbstractHandler{/// <summary>/// 处理请假请求/// </summary>public override void HandleRequest(LeaveRequest request){if (request.leaveDays<=3){Console.WriteLine($"直接领导(一级领导)已经批准{request.name}的请假请求,请假天数:{request.leaveDays}");}else{if (this.NextHandler!=null){this.NextHandler.HandleRequest(request);}else{Console.WriteLine($"{request.name}请假天数太多,没有人批准该假条!");}}}}/// <summary>/// 二级领导/// </summary>public class LeaderHandler2 : AbstractHandler{/// <summary>/// 处理请假请求/// </summary>public override void HandleRequest(LeaveRequest request){if (request.leaveDays > 3 && request.leaveDays <= 7){Console.WriteLine($"二级领导已经批准{request.name}的请假请求,请假天数:{request.leaveDays}");}else{if (this.NextHandler != null){this.NextHandler.HandleRequest(request);}else{Console.WriteLine($"{request.name}请假天数太多,没有人批准该假条!");}}}}/// <summary>/// 最高领导(三级)/// </summary>public class LeaderHandler3 : AbstractHandler{/// <summary>/// 处理请假请求/// </summary>public override void HandleRequest(LeaveRequest request){if (request.leaveDays > 7 && request.leaveDays <= 30){Console.WriteLine($"最高领导(三级)已经批准{request.name}的请假请求,请假天数:{request.leaveDays}");}else{if (this.NextHandler != null){this.NextHandler.HandleRequest(request);}else{Console.WriteLine($"{request.name}请假天数太多,没有人批准该假条!");}}}}
客户单创建责任链并调用:
//1. 有人要请假LeaveRequest myRequest1 = new LeaveRequest() { name="小明",leaveDays=6};LeaveRequest myRequest2 = new LeaveRequest(){name = "小王",leaveDays = 2};LeaveRequest myRequest3 = new LeaveRequest(){name = "小放",leaveDays = 15};LeaveRequest myRequest4 = new LeaveRequest(){name = "张三",leaveDays = 35};//2. 请假相关的责任链LeaderHandler1 handler1 = new LeaderHandler1();LeaderHandler2 handler2 = new LeaderHandler2();LeaderHandler3 handler3 = new LeaderHandler3();handler1.NextHandler = handler2;handler2.NextHandler = handler3;//3.进行请假处理handler1.HandleRequest(myRequest1);handler1.HandleRequest(myRequest2);handler1.HandleRequest(myRequest3);handler1.HandleRequest(myRequest4);
测试结果:
4. 适用场景分析
(1). 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
(2). 可动态指定一组对象处理请求,或添加新的处理者。
(3). 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
二. 迭代器模式
1. 背景
在现实生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如【数据结构】中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方式不利于程序的扩展,如果要更换遍历方法就必须修改程序源代码,这违背了 “开闭原则”。既然将遍历方法封装在聚合类中不可取,那么聚合类中不提供遍历方法,将遍历方法由用户自己实现是否可行呢?答案是同样不可取,因为这种方式会存在两个缺点:
A. 暴露了聚合类的内部表示,使其数据不安全;
B. 增加了客户的负担。
“迭代器模式”能较好地克服以上缺点,它在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”。比如C#中的List就实现了迭代器模式。
2. 定义和特点
(1). 定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
(2). 优点:
A. 访问一个聚合对象的内容而无须暴露它的内部表示。
B. 遍历任务交由迭代器完成,这简化了聚合类。
C. 它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历。
D. 增加新的聚合类和迭代器类都很方便,无须修改原有代码。
E. 封装性良好,为遍历不同的聚合结构提供一个统一的接口。
(3). 缺点:
增加了类的个数,这在一定程度上增加了系统的复杂性
3. 具体实现
(1). 模式结构
迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。
A. 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
B. 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
C. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
D. 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
结构如下图:
(2). 使用场景
见下面代码模拟。
(3). 代码实操
聚合接口和具体的聚合类
/// <summary>/// 抽象聚合接口/// </summary>public interface IAggregate<T>{public void Add(T obj);public void Remove(T obj);/// <summary>/// 获取聚合对象的迭代器/// </summary>/// <returns></returns>public Iterator<T> GetIterator();}/// <summary>/// 具体聚合/// </summary>public class ConcreteAggregate<T> : IAggregate<T>{private List<T> list = new List<T>();public void Add(T obj){list.Add(obj);}public void Remove(T obj){list.Remove(obj);}/// <summary>/// 获取迭代器/// </summary>/// <returns></returns>public Iterator<T> GetIterator(){return new ConcreteIterator<T>(list);}}
抽象迭代器和具体的迭代器
/// <summary>/// 抽象迭代器/// </summary>public interface Iterator<T>{T First();T Next();bool HasNext();}/// <summary>/// 具体的迭代器/// </summary>/// <typeparam name="T"></typeparam>public class ConcreteIterator<T> : Iterator<T>{private List<T> list = null;private int index = 0;public ConcreteIterator(List<T> myList){this.list = myList;}public T First(){return list[0];}public bool HasNext(){if (index<list.Count-1){return true;}else{return false;}}public T Next(){T obj =default(T);if (this.HasNext()){obj = list[++index];}return obj;}}
测试
{//聚合对象添加数据IAggregate<string> ag = new ConcreteAggregate<string>();ag.Add("001");ag.Add("002");ag.Add("003");ag.Add("004");//获取对应的迭代器Iterator<string> it = ag.GetIterator();//输出数据Console.WriteLine($"第一个元素为:{it.First()}");Console.WriteLine("剩下的元素为:");while (it.HasNext()){Console.WriteLine(it.Next());}
}
运行结果
4. 适用场景分析
(1). 当需要为聚合对象提供多种遍历方式时。
(2). 当需要为遍历不同的聚合结构提供一个统一的接口时。
(3). 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。
PS: 由于聚合与迭代器的关系非常密切,所以大多数语言在实现聚合类时都提供了迭代器类,因此大数情况下使用语言中已有的聚合类的迭代器就已经够了。
原文链接:https://www.cnblogs.com/yaopengfei/p/13489597.html
相关文章:
设计模式第六讲:责任链模式和迭代器模式详解
一. 责任链模式1. 背景在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批…...
K8s 架构简介(一)
一、前言 在开始学习K8s之前,让我们对容器有一个基本的了解 1.1 什么是容器 一个容器镜像是一个可运行的软件包,其中包含了一个完整的可执行程序,包括代码和运行时需要应用、系统库和全部重要设置的默认值。 通过将应用程序本身ÿ…...
xshell6运行报错:由于找不到mfc110u.dll、MSVCR110.dll无法继续执行代码
今天给大家分享一下我刚装完系统遇到得问题,由于新盟的罗建雨【胡巴】老师帮我给电脑加了固态,又重装了系统,因此电脑里面得所有软件需要重装,在我重装的过程中遇到了一个小问题给大家分享一下,如果大家以后遇到也方便解决。 问题: 安装Xshell时电脑系统报错:“由于找…...
Baklib知识库管理平台,协助组织提升知识管理水平
随着信息时代和知识经济时代的到来,企业内部信息资料繁多冗杂,知识管理逐渐成为各大企业的重要工作之一,企业管理者无不感受到巨大的压力,怎么样将知识进行有效的管理,成为一个难点,并且随着信息不断的更迭…...
一文搞懂core-scheduling核心机制
cookie的原理借助于unsigned long型,和refcount_t引用计数器。 32位64位char *4字节8字节unsigned long4字节8字节 数据结构修改 首先看看实现core scheduling功能对数据结构有哪些修改 task_struct struct task_struct{struct rb_node core_node;unsigned long…...
IP地址在金融行业有哪些应用?
中国加入WTO以来经济得到迅速发展,金融行业随着经济发展体系越来越完善。随着西方金融公司和理念的加入中国金融行业开始多样化发展。金融行业在快速发展的同时也引发了许多弊端。如何维护挖掘客户更大需求?如何获取更多优质客户?如何提升网络…...
GT-suite v2016解决许可证过期问题(附新版liscense下载地址)
安装GT-suite v2016时遇到了如图报错的问题。当时的报错找不到了,下图是贴吧相同问题的报错图。 为了解决问题,先根据某网友的如下答复操作: 添加环境变量后仍然有相同报错。 看来需要寻找其他方法。 再尝试着卸载GT-suite v2016,…...
小红书商业笔记与普通笔记区别是什么?小红书笔记有哪几种
主攻单一平台,如何迅速打造爆文。针对软文发布类别的选择,小红书商业笔记与普通笔记区别究竟是什么,今天为大家带来的详细分析,告诉你该如何用最少的成本,做出“爆文”。1、小红书的笔记类型我们都知道,小红…...
DataWhale-统计学习方法打卡Task01
学习教材《统计学习方法(第二版)》李航 统计学习方法(第2版) by...李航 (z-lib.org).pdf https://www.aliyundrive.com/s/maJZ6M9hrTe 点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无…...
Java面试——Spring 事务
目录 1.什么是Spring 事务 2.Spring 事务的开启方式 3.Spring事务的实现方式/原理 4.事务传播机制 5.事务隔离级别 6.事务失效的原因 1.什么是Spring 事务 事务在逻辑上是一组操作,要么执行,要不都不执行。 如下: Begin; insert into…...
Python语言零基础入门教程(十九)
Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。 1、异常处理 2、断言(Assertions) python标准异常 什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生&…...
重生之我是赏金猎人-SRC漏洞挖掘(一)-某SRC测试系统无脑Getshell
0x01 前言 https://github.com/J0o1ey/BountyHunterInChina 欢迎大佬们点个star 0x02 资产收集到脆弱系统 在某src挖掘过程中,本人通过ssl证书对域名资产进行了收集,通过计算域名对应ip段的权重 整理出其C段资产,进行了批量目录扫描 查看…...
Sciter 结合 PReact 实现组件公共逻辑抽离
Sciter 结合 PReact 实现组件公共逻辑抽离 下面例子是获取鼠标移动位置,将这部分逻辑进行抽离 一、使用高阶组件抽离公共逻辑 import {Component } from ./preact.js; export const HOCFactory = (Component) => {class HOC...
OpenTracing协议规范链接
一、官网链接 OpenTracing specificationhttps://opentracing.io/specification/不过目前OpenTracing项目已归档,不再维护。需要参考OpenTelemetry官网链接 Migrating from OpenTracing | OpenTelemetryBackward compatibility with OpenTracing has been a prior…...
金三银四面试必看,自动化测试如何解决日志问题
前言 前几天在员群里,有同学问了一个自动化测试实践中遇到的问题: 持续集成的自动化用例很多,测试环境日志level为debug,日志量大概40G/每天,定位问题时日志查询很慢,该怎么解决? 这个问题可…...
微信怎么开小店?【企业商家微信开店】
企业商家入局微信做营销已经是经营规划中必须做的一件事了,对于企业商家来说,最简单直接的方式就是开一个微信小店,然后通过自己宣传推广来在微信小店中成商品。那么企业商家在微信怎么开小店呢?下面内容分享给想在微信开店的企业…...
Java 中FastJson的使用【吃透FastJson】
如果不了解JSON格式,建议先看下:JSON数据格式【学习记录】 JSON序列化、反序列化JavaBean的框架有很多,最常见的Jackson、阿里巴巴开源的FastJson、谷歌的GSON、apache提供的json-lib等,下面我们主要来熟悉一下:Java语…...
Redis5.0集群搭建
Redis集群教程 此文重在介绍 Redis5.0 三主三从集群安装,无复杂难懂的概念,若想深入了解集群原理请参考Redis集群规范。 Redis集群介绍 Redis Cluster 提供一种 Redis 安装方式:数据自动在多个 Redis 节点间分片。 Redis Cluster 提供一定…...
继企业级信息系统开发学习1.1 —— Spring配置文件管理Bean
骑士救美计划采用构造方法注入属性值1、创建救美任务类2、创建救美骑士类2、创建救美骑士类3、创建旧救美骑士测试类3、配置救美骑士Bean5、创建新救美骑士测试类采用构造方法注入属性值 1、创建救美任务类 在net.huawei.spring.day01包里创建RescueDamselQuest类 Rescue Da…...
Web 容器、HTTP 服务器 、Servlet 容器区别与联系
首先浏览器发起 HTTP 请求,像早期的时候只会请求一些静态资源,这时候需要一个服务器来处理 HTTP 请求,并且将相应的静态资源返回。 这个服务器叫 HTTP 服务器。 简单点说就是解析请求,然后得知需要服务器上面哪个文件夹下哪个名字…...
eBPF 进阶: 内核新特性进展一览
Linux 内核在 2022 年主要发布了 5.16-5.19 以及 6.0 和 6.1 这几个版本,每个版本都为 eBPF 引入了大量的新特性。本文将对这些新特性进行一点简要的介绍,更详细的资料请参考对应的链接信息。总体而言,eBPF 在内核中依然是最活跃的模块之一&a…...
2.输入子系统学习-multi-touch-protocol-2023.02
Documentation/input/multi-touch-protocol.txt(百度翻译) Multi-touch (MT) Protocol ------------------------- Copyright (C) 2009-2010 Henrik Rydberg <rydbergeuromail.se> 一、Introduction ------------ In order to utilize t…...
【靶机】vulnhub靶机pylington
靶机下载地址 Pylington: 1 ~ VulnHub kali ip:192.168.174.128 靶机ip:192.168.174.146 arp-scan -l发现靶机ip是192.168.174.146 进行靶机的端口扫描,这里使用的是nmap的gui 可以发现开放了21和80端口,80端口扫描到了robot…...
【大数据】大数据学习路线
职位选择 首先明确一点:大数据涉及的知识面广度还是有的,需要学习的组件繁多,想要每一项精通几乎不可能,所以企业在招聘的时候会进行细分,基于某个方向进行招聘,比如关键字,数据仓库工程师、数…...
【Python爬虫案例教学】采集某网站壁纸,实现壁纸自由
前言 (。・∀・)ノ゙嗨 大家好,这里是小圆 现在开始每天都给大家 分享些关于python爬虫的案例教学 从最简单的开始 — 采集图片壁纸 今天就来扒拉这个优质的壁纸网站~ 网址 👇 顺便瞧一眼 这里的…...
波卡2022年第四季度报告
本文将介绍Messari最新发布的波卡Polkadot 2022年第四季度报告内容。 1 Messari已经发布关于波卡Polkadot最新的报告:显示了2022年第四季度的日活账户增加了64%,新用户增长49%。 2 Messari指出,波卡中继链在2022第四季度的环比增长令人印象…...
第一章:初始化react项目+antd+less
初始化react项目 我们首先使用react脚手架创建一个项目 Ant Design less creact-react-app中文文档 creact-react-app demo生产环境打包运行 当我们执行了 npm run build 打包后直接访问index.html 看效果白屏 这时候就需要安装一个serve包 npm install -g serve当我们安…...
图的基本概念
1、图的概念 G(V,E) 图G由节点集合VV(G)和边集合EE(G)组成,其中V为非空有限集合。 集合V中的节点(node)用红色标出,通过集合E中黑色的边(edge)连接。 G的边:E中的每个顶点对&#x…...
MySQL必会四大函数-窗口函数
在了解窗口函数之前,我们必须了解聚合函数。常见的聚合函数,包括 AVG、COUNT、MAX、MIN、SUM 以及 GROUP_CONCAT,常和GROUP BY 函数一起使用。聚合函数的作用就是对一组数据行进行汇总计算,并且返回单个分析结果。 窗口函数和聚合…...
各CCF期刊点评网站/学术论坛的信息汇总及个人评价
CCF中文期刊投稿选择之篇章一:各CCF期刊点评网站/学术论坛的信息汇总及个人评价中文科技期刊A类(EI检索)中文期刊投稿点评网站整理1.小木虫学术论坛2. Letpub3. Justscience4. 发表记5. 会伴(Conference Partner)6. ijouranl7. 掌桥科研这是以…...
一家专做节日商品的网站/考研培训班集训营
这两天收到一SQL 2008 R2数据库服务器的磁盘空间告警,在检查过程中发现ReportServerTempDB已经暴增到60多GB,其中数据文件接近60G,日志文件9G大小左右。如下截图所示 我们知道ReportServerTempDB是SSRS使用的临时数据库。这个数据库负责存储中…...
网上做公务员考题的网站/广州最新新闻
1/**//// <summary> 2 /// 从DataTable中查询数据 3 /// </summary> 4 /// <param name"tb">待处理的DataTable</param> 5 /// <param name"expression">找匹配(条件)(不用where ,直接就"…...
网站开发费用如何入账/百度广告点击一次多少钱
10W无线充电发射端电路设计参考,是一款基于IP6806无线充SOC芯片设计的符合Qi标准,无线发射功率10W的无线充方案,输入参数:9V1.6A,输出参数:9V1.12A;5V1A等IP6806是一款无线充电发射端控制SoC芯片…...
有什么好的提供外链网站/最新营销模式
PHPsocket函数讲解PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。大家知道phpsocket函数…...
网址大全2345色综合导航/最专业的seo公司
urllib-Python3文档链接致谢python修行路 1.初识urllib urllib库包含以下模块: urllib.request——打开和读取 URLsurllib.error——urllib.request异常处理urllib.parse——解码URLsurllib.robotparser——解码robots.txt 2.urllib爬虫 2.1 简单的get方法 简…...
网站建设_seo技术支持/网络运营好学吗
接前面。 回到程序调用关系上来: estimate_rel_size -> RelationGetNumberOfBlocks->RelationGetNumberOfBlocksINFork ->Smgrnblocks->mdnblocks... 折腾了一圈,就是为了评估一个表的大小。 那么,我们所获得的block,…...