迭代器模式(Iterator)

迭代器模式是一种行为设计模式,可以在不暴露底层实现(列表、栈或树等)的情况下,遍历一个聚合对象中所有的元素。

Iterator is a behavior design pattern that can traverse all elements of an aggregate object 
without exposing the internal implementation (list, stack, tree, etc.).

结构设计

迭代器模式包含如下角色:
Iterator,迭代器基类,声明遍历聚合对象所需的操作:获取下一个元素、获取当前位置、下一个元素是否存在等。
ConcreteIterator,迭代器实现类,实现遍历聚合对象的算法。
Aggregate,聚合基类,声明一个获取迭代器的接口。
ConcreteAggregate,具体聚合实现类,实现获取一个迭代器的接口并返回一个具体迭代器实例。
Client,客户端,通过聚合基类和迭代器基类的接口与两者进行交互。
迭代器模式类图表示如下:
请添加图片描述

伪代码实现

接下来将使用代码介绍下迭代器模式的实现。

// 1、聚合接口,声明一个获取迭代器的接口,以及元素添加及删除接口
public interface IAggregate {
    IIterator createIterator();

    void append(Object element);

    void removeLast();
}

//2、具体聚合实现类,获取一个迭代器的接口,并实现元素添加及删除接口,这里使用数组存储元素
public class ConcreteAggregate implements IAggregate {
    private String[] elements;

    private int cursor = -1;

    public ConcreteAggregate(int size) {
        elements = new String[size];
    }

    @Override
    public void append(Object element) {
        cursor++;
        elements[cursor] = (String) element;
    }

    @Override
    public void removeLast() {
        elements[cursor] = "";
        cursor--;
    }

    public int getCursor() {
        return this.cursor;
    }

    public String[] getElements() {
        return this.elements;
    }

    @Override
    public IIterator createIterator() {
        return new ConcreteIterator(this);
    }
}

// 3、迭代器接口,声明遍历聚合对象所需的操作:获取下一个元素、获取当前位置、下一个元素是否存在等
public interface IIterator {
    Object first();

    Object next();

    boolean hasNext();

    Object currentItem();
}

// 4、迭代器实现类,实现遍历聚合对象的算法,及其他已声明接口
public class ConcreteIterator implements IIterator {
    private ConcreteAggregate aggregate;

    private int index;

    public ConcreteIterator(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
        this.index = 0;
    }

    @Override
    public Object first() {
        String[] elements = aggregate.getElements();
        return elements[0];
    }

    @Override
    public Object next() {
        int cursor = aggregate.getCursor();
        if (cursor < 0 || index > cursor) {
            return null;
        }
        String[] elements = aggregate.getElements();
        return elements[index++];
    }

    @Override
    public boolean hasNext() {
        int cursor = aggregate.getCursor();
        if (cursor < 0 || index > cursor) {
            return false;
        }
        return true;
    }

    @Override
    public Object currentItem() {
        int cursor = aggregate.getCursor();
        if (cursor < 0 || index > cursor) {
            return null;
        }
        String[] elements = aggregate.getElements();
        return elements[index];
    }
}

// 5、客户端
public class IteratorClient {
    public void test() {
        // (1) 创建迭代对象实例
        IAggregate aggregate = new ConcreteAggregate(10);
        // (2) 增删元素
        aggregate.append("hello");
        aggregate.append("world");
        aggregate.append("foo");
        aggregate.removeLast();
        // (3) 获取迭代器实例
        IIterator iterator = aggregate.createIterator();
        // (4) 执行遍历操作
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

适用场景

在以下情况下可以考虑使用迭代器模式:
(1) 当聚合对象的数据结构较复杂,且希望对客户端隐藏其复杂性时(出于易用性或安全性考虑),可考虑使用迭代器模式。迭代器封装了与复杂数据结构进行交互的细节,为客户端提供多个访问集合元素的简单方法。
这种方式不仅对客户端来说非常方便,而且能避免客户端在直接与集合交互时执行错误或有害的操作,从而起到保护集合的作用。
(2) 使用该模式可以减少程序中重复的遍历代码。重要迭代算法的代码往往体积非常庞大。当这些代码被放置在程序业务逻辑中时,它会让原始代码的职责模糊不清,降低其可维护性。因此,
将遍历代码移到特定的迭代器中可使程序代码更加精炼和简洁。
(3) 如果希望代码能够遍历不同的甚至是无法预知的数据结构,可考虑使用迭代器模式。该模式为集合和迭代器提供了一些通用接口。如果在代码中使用了这些接口,那么将其他实现了这些接口的集合和迭代器传递给它时,
它仍将可以正常运行。

优缺点

迭代器模式有以下优点:
(1) 符合单一职责原则。通过将体积庞大的遍历算法代码抽取为独立的类,可对客户端代码和集合进行整理。
(2) 符合开闭原则。可实现新型的集合和迭代器并将其传递给现有代码,无需修改现有代码。
(3) 可以并行遍历同一集合,因为每个迭代器对象都包含其自身的遍历状态。
但是该模式也存在以下缺点:
(1) 如果只与简单的集合进行交互,应用该模式可能会矫枉过正。
(2) 对于某些特殊集合,使用迭代器可能比直接遍历的效率低。
(3) 增加了系统的复杂性。因为迭代器模式将存储数据和遍历数据的职责分离,增加了新的聚合类需要对应增加新的迭代器类,增加了系统的复杂性。

参考

《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/mediator.html 迭代器模式
https://refactoringguru.cn/design-patterns/mediator 迭代器模式
https://www.runoob.com/design-pattern/mediator-pattern.html 迭代器模式
https://www.cnblogs.com/adamjwh/p/10959987.html 简说设计模式——迭代器模式

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SIFT算法原理:SIFT算法详细介绍

前面我们介绍了Harris和Shi-Tomasi角点检测算法&#xff0c;这两种算法具有旋转不变性&#xff0c;但不具有尺度不变性&#xff0c;以下图为例&#xff0c;在左侧小图中可以检测到角点&#xff0c;但是图像被放大后&#xff0c;在使用同样的窗口&#xff0c;就检测不到角点了。…

uniapp微信小程序中打开腾讯地图获取用户位置信息

实现的效果 第一步&#xff1a;首先登录微信公众平台 , 需要用到AppID 第二步&#xff1a; 注册登录腾讯位置服务 注册需要手机号和邮箱确认&#xff0c;然后创建应用 创建后点击添加key 添加后会生成key&#xff0c;后面会用到这个key 第三步&#xff1a; 登录微信公众平台&a…

Git Submodule 更新子库失败 fatal: Unable to fetch in submodule path

编辑本地目录 .git/config 文件 在 [submodule “Assets/CommonModule”] 项下 加入 fetch refs/heads/:refs/remotes/origin/

记录下:win10 AMD CPU 下载 Chromium 源码并编译(版本 103.0.5060.66)

文章目录 一、一些主要地址连接二、环境配置1、如何找官方环境文档&#xff1a;1.1 如何找到这个不同版本的文档&#xff1a; 2、电脑配置&#xff1a;3、visual studio 2019安装&#xff1a;3.1 社区版下载&#xff1a;3.2 安装配置&#xff1a; 4、debugtools配置4.1 如何判断…

LeetCode每日一题——1331.数组序号转换

题目传送门 题目描述 给你一个整数数组 arr &#xff0c;请你将数组中的每个元素替换为它们排序后的序号。 序号代表了一个元素有多大。序号编号的规则如下&#xff1a; 序号从 1 开始编号。一个元素越大&#xff0c;那么序号越大。如果两个元素相等&#xff0c;那么它们的…

上市公司-上下游和客户数据匹配(2001-2022年)

参考《中国工业经济》中陶锋&#xff08;2023&#xff09;的做法&#xff0c;对上市公司的上下游供应商和客户数据进行匹配。形成“上游供应商—目标企业—下游客户一年度数据集”。该是关于上市公司的上下游以及客户数据匹配的详细信息。 它呈现出由各种上游供应商和下游客户…

mysql高级三:sql性能优化+索引优化+慢查询日志

内容介绍 单表索引失效案例 0、思考题&#xff1a;如果把100万数据插入MYSQL &#xff0c;如何提高插入效率 &#xff08;1&#xff09;关闭自动提交&#xff0c;只手动提交一次 &#xff08;2&#xff09;删除除主键索引外其他索引 &#xff08;3&#xff09;拼写mysql可以执…

ELK日志分析系统简介

ELK日志分析系统简介 ElasticsearchLogstashKibana主要功能Kibana日志处理步骤ELK的工作原理 日志服务器 提高安全性 集中存放日志 缺陷 ​ 对日志的分析困难 ELK日志分析系统 Elasticsearch 概述:提供了一个分布式多用户能力的全文搜索引擎 核心概念 接近实时 集群 节…

特性Attribute

本文只提及常用的特性&#xff0c;更多特性请查看官方文档。 AddComponentMenu - Unity 脚本 API 常用特性 AddComponentMenu 添加组件菜单 使用 AddComponentMenu 属性可在“Component”菜单中的任意位置放置脚本&#xff0c;而不仅是“Component > Scripts”菜单。 使用…

GODOT游戏引擎简介,包含与unity性能对比测试,以及选型建议

GODOT&#xff0c;是一个免费开源的3D引擎。本文以unity作对比&#xff0c;简述两者区别和选型建议。由于是很久以前写的ppt&#xff0c;技术原因视频和部分章节丢失了。建议当做业务参考。 GODOT目前为止遇到3个比较重大的基于&#xff0c;第一个是oprea的合作奖&#xff0c;…

嵌入式开发学习(STC51-13-温度传感器)

内容 通过DS18B20温度传感器&#xff0c;在数码管显示检测到的温度值&#xff1b; DS18B20介绍 简介 DS18B20是由DALLAS半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器&#xff1b; 与传统的热敏电阻等测温元件相比&#xff0c;它是一…

【C++】map和set

目录 一、容器补充1.序列式容器与关联式容器2.键值对3.树形结构的关联式容器 二、set1.set的介绍2.set的使用3.multset的介绍4.multset的使用 三、map1.map的介绍2.map的使用3.multimap的介绍4.multimap的使用 一、容器补充 1.序列式容器与关联式容器 我们已经接触过STL中的部…

Mysql自动同步的详细设置步骤

以下步骤是真实的测试过程&#xff0c;将其记录下来&#xff0c;与大家共同学习。 一、环境说明&#xff1a; 1、主数据库&#xff1a; &#xff08;1&#xff09;操作系统&#xff1a;安装在虚拟机中的CentOS Linux release 7.4.1708 (Core) [rootlocalhost ~]# cat /etc/redh…

Docker学习(二十四)报错速查手册

目录 一、This error may indicate that the docker daemon is not running 报错docker login 报错截图&#xff1a;原因分析&#xff1a;解决方案&#xff1a; 二、Get "https://harbor.xxx.cn/v2/": EOF 报错docker login 报错截图&#xff1a;原因分析&#xff1a…

使用ubuntu-base制作根文件系统

1&#xff1a;ubuntu官网下载最小根文件系统&#xff1a; 放置到电脑的ubuntu中&#xff0c; Mkdir Ubuntu_rootfs Cd Ubuntu_rootfs Sudo tar –zxvf Ubuntu-bash-xxxxxx.tar.gz 2&#xff1a;电脑的ubuntu安装qemu搭建arm模拟系统 将/usr/bin/qemu-arm-static/(64位拷贝…

(黑客)自学笔记

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 行为&#xff1a;从编程开始掌握&#xff0c;前端后端、通信协议、什么都学。 缺点&#xff1a;花费时间太长、实际向安全过渡后可用到的关键知识并不多。…

Java基础面试题2

Java基础面试题 一、IO和多线程专题 1.介绍下进程和线程的关系 进程&#xff1a;一个独立的正在执行的程序 线程&#xff1a;一个进程的最基本的执行单位&#xff0c;执行路径 多进程&#xff1a;在操作系统中&#xff0c;同时运行多个程序 多进程的好处&#xff1a;可以充…

[webpack] 基本配置 (一)

文章目录 1.基本介绍2.功能介绍3.简单使用3.1 文件目录和内容3.2 下载依赖3.3 启动webpack 4.基本配置4.1 五大核心概念4.2 基本使用 1.基本介绍 Webpack 是一个静态资源打包工具。它会以一个或多个文件作为打包的入口, 将我们整个项目所有文件编译组合成一个或多个文件输出出去…

macbook怎么卸载软件?2023年最新全新解析macbook电脑怎样删除软件

macbook怎么卸载软件&#xff1f;2023年最新全新解析macbook电脑怎样删除软件。关于Mac笔记本如何卸载软件_Mac笔记本卸载软件的四种方法的知识大家了解吗&#xff1f;以下就是小编整理的关于Mac笔记本如何卸载软件_Mac笔记本卸载软件的四种方法的介绍&#xff0c;希望可以给到…

LeetCode 热题 100 JavaScript--206. 反转链表

/*** Definition for singly-linked list.* function ListNode(val, next) {* this.val (valundefined ? 0 : val)* this.next (nextundefined ? null : next)* }*/ /*** param {ListNode} head* return {ListNode}*/1、逐个断键&#xff0c;将后一个节点放到前面 …