Java 设计模式——迭代器模式

news2024/11/17 12:42:24

目录

  • 1.概述
  • 2.结构
  • 3.案例实现
    • 3.1.抽象迭代器
    • 3.2.具体迭代器
    • 3.3.抽象聚合
    • 3.4.具体聚合
    • 3.5.测试
  • 4.优缺点
  • 5.使用场景
  • 6.JDK 源码解析——Iterator

1.概述

迭代器模式 (Iterator Pattern) 是一种行为型设计模式,它提供一种顺序访问聚合对象(如列表、集合等)中的元素,而无需暴露聚合对象的内部表示。迭代器模式将遍历逻辑封装在一个迭代器对象中,使得我们可以使用统一的方式遍历不同类型的聚合对象,同时也可以简化客户端代码。

2.结构

迭代器模式主要包含以下角色:

  • 抽象聚合 (Aggregate) 角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。
  • 具体聚合 (ConcreteAggregate) 角色:实现抽象聚合类,返回一个具体迭代器的实例。
  • 抽象迭代器 (Iterator) 角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()next() 等方法。
  • 具体迭代器 (Concretelterator) 角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

3.案例实现

【例】定义一个可以存储学生对象的容器对象,将遍历该容器的功能交由迭代器实现,其类图如下:
在这里插入图片描述

具体实现代码如下:
Student.java

public class Student {
    private String name;
    private String number;
    
    public Student() {
    }
    
    public Student(String name, String number) {
        this.name = name;
        this.number = number;
    }
    
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", number='" + number + '\'' +
                '}';
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String getNumber() {
        return number;
    }
    
    public void setNumber(String number) {
        this.number = number;
    }
}

3.1.抽象迭代器

StudentIterator.java

//抽象迭代器角色接口
public interface StudentIterator {
    //判断是否还有元素
    boolean hasNext();
    
    //获取下一个元素
    Student next();
}

3.2.具体迭代器

StudentIteratorImpl.java

//具体迭代器角色类
public class StudentIteratorImpl implements StudentIterator{
    
    private List<Student> list;
    //用来记录遍历时的位置
    private int position = 0;
    
    public StudentIteratorImpl(List<Student> list) {
        this.list = list;
    }
    
    @Override
    public boolean hasNext() {
        return position < list.size();
    }
    
    @Override
    public Student next() {
        //从集合中或者去指定位置的元素
        Student currentStudent = list.get(position);
        position++;
        return currentStudent;
    }
}

3.3.抽象聚合

StudentAggregate.java

//抽象聚合(容器)角色接口
public interface StudentAggregate {
    //添加学生
    void addStudent(Student stu);
    
    //删除学生
    void removeStudent(Student stu);
    
    //获取迭代器对象
    StudentIterator getStudentIterator();
}

3.4.具体聚合

StudentAggregateImpl.java

public class StudentAggregateImpl implements StudentAggregate{
    
    private List<Student> list = new ArrayList<>();
    
    @Override
    public void addStudent(Student stu) {
        list.add(stu);
    }
    
    @Override
    public void removeStudent(Student stu) {
        list.remove(stu);
    }
    
    //获取迭代器对象
    @Override
    public StudentIterator getStudentIterator() {
        return new StudentIteratorImpl(list);
    }
}

3.5.测试

Client.java

public class Client {
    public static void main(String[] args) {
        //创建聚合(容器)对象
        StudentAggregateImpl aggregate = new StudentAggregateImpl();
        Student student1 = new Student("Tom", "1001");
        Student student2 = new Student("Mike", "1002");
        Student student3 = new Student("Jerry", "1003");
        Student student4 = new Student("Mary", "1004");
        //添加元素
        aggregate.addStudent(student1);
        aggregate.addStudent(student2);
        aggregate.addStudent(student3);
        aggregate.addStudent(student4);
        
        //删除元素
        aggregate.removeStudent(student3);
        
        //遍历聚合对象
        // 1.获取迭代器对象
        StudentIterator iterator = aggregate.getStudentIterator();
        // 2.遍历
        while (iterator.hasNext()){
            // 3.获取元素
            Student student = iterator.next();
            System.out.println(student.toString());
        }
    }
}

结果如下:

Student{name='Tom', number='1001'}
Student{name='Mike', number='1002'}
Student{name='Mary', number='1004'}

4.优缺点

(1)迭代器模式的优缺点如下:

  • 优点
    • 简化客户端代码:迭代器模式将遍历逻辑封装在迭代器对象中,客户端代码只需通过迭代器接口与迭代器对象交互,无需关心具体的遍历算法和聚合对象的内部结构,从而简化了客户端代码。
    • 统一遍历接口:迭代器模式提供一种统一的遍历接口,使得对不同类型的聚合对象可以使用相同的遍历方式,提供了更加灵活和通用的遍历操作。
    • 支持多种遍历方式:通过不同的迭代器实现,迭代器模式支持多种遍历方式,如顺序遍历、逆序遍历等,使得遍历操作更加灵活可变。
    • 解耦聚合对象与遍历操作:迭代器模式将遍历操作从聚合对象中分离出来,使得聚合对象的内部结构不再暴露给客户端,遵循了单一职责原则,提高了代码的可维护性和可扩展性。
  • 缺点
    • 对于某些较为复杂的聚合对象,实现迭代器可能会比较复杂,需要实现多个方法,并考虑并发访问的线程安全性,增加了代码的复杂性。
    • 当遍历的聚合对象发生变化时,需要相应地修改迭代器的实现,可能会影响到迭代器的逻辑。

(2)总体来说,迭代器模式适用于需要统一遍历接口、封装遍历逻辑、解耦聚合对象与遍历操作的场景。它可以提供更加灵活、通用和可维护的遍历操作,但在某些情况下,可能会增加代码的复杂性。因此,在使用迭代器模式时需要综合考虑具体的设计需求和项目情况。

5.使用场景

(1)迭代器模式通常适用于以下场景:

  • 需要遍历聚合对象的元素:当需要遍历并访问聚合对象中的元素,并且不希望暴露聚合对象的内部结构给客户端时,可以使用迭代器模式。它可以将遍历操作封装在迭代器中,提供一个统一的遍历接口。
  • 需要对不同类型的聚合对象使用统一的遍历方式:迭代器模式提供了一种统一的遍历接口,使得对不同类型的聚合对象可以使用相同的遍历方式。这样可以增加代码的灵活性和可维护性,使得客户端代码更加通用。
  • 需要支持多种遍历方式:如果需要支持多种遍历方式,如顺序遍历、逆序遍历等,可以通过不同的迭代器实现来实现不同的遍历方式。这样可以使遍历操作更加灵活可变。
  • 需要屏蔽聚合对象的内部实现细节:当聚合对象的内部结构较为复杂,或者不希望暴露内部结构给客户端时,可以使用迭代器模式进行封装。迭代器模式将遍历逻辑封装在迭代器对象中,客户端无需关心聚合对象的具体实现细节。
  • 需要遍历操作与聚合对象解耦:迭代器模式将遍历操作从聚合对象中分离出来,使得聚合对象的内部结构不再暴露给客户端。这样可以提高代码的可维护性和可扩展性,使遍历操作与聚合对象解耦。

(2)迭代器模式在现实生活中的应用也非常广泛,例如集合类、数据库查询结果等都可以使用迭代器模式来统一遍历操作接口。

6.JDK 源码解析——Iterator

(1)迭代器模式在 Java 的很多集合类中被广泛应用,接下来看下面的例子:

public class TestArratList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //添加元素
        list.add("1001");
        list.add("1002");
        list.add("1003");
        //删除元素
        list.remove("1003");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

结果如下:

1001
1002

(2)看完这段代码是不是觉得很熟悉,它与我们上面的代码基本类似。单列集合都使用到了迭代器,所以现在以 ArrayList 举例来说明:

  • List:抽象聚合类;
  • ArrayList:具体的聚合类;
  • Iterator:抽象迭代器;
  • list.iterator():返回的是实现了 Iterator 接口的具体迭代器对象;

(3)具体来看看 ArrayList 的部分关键代码实现:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
        int cursor;       	// 下一个要返回元素的索引
        int lastRet = -1; 	// 上一个返回元素的索引
        int expectedModCount = modCount;

        Itr() {}
		
        //判断是否还有元素
        public boolean hasNext() {
            return cursor != size;
        }

        //获取下一个元素
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        
        //...
}

(4)这部分代码大致就是在 iterator 方法中返回了一个实例化的 Iterator 对象。Itr 是一个内部类,它实现了 Iterator 接口并重写了其中的抽象方法。此外,通过下图可知 ArrayList 与 Iterable 的关系:

在这里插入图片描述

package java.lang;

import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;

public interface Iterable<T> {
    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

(5)当我们在使用 Java 开发的时想使用迭代器模式的话,只要让我们自己定义的容器类实现 java.util.Iterable 并实现其中的 iterator() 方法使其返回一个 java.util.Iterator 的实现类就可以了。

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

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

相关文章

JVM学习之内存与垃圾回收篇1

文章目录 1 JVM与Java体系结构1.0 Java发展重大事件1.1 虚拟机和Java虚拟机1.3 JVM整体结构1.4 Java代码执行流程1.5 JVM架构模型1.6 JVM的生命周期1.7 JVM发展历程 2 类加载子系统2.1 ClassLoader2.2 用户自定义类加载器2.2.1 为什么需要自定义类加载器2.2.2 自定义类加载器的…

【框架篇】对象注入的三种实现方式

对象注入的实现 一&#xff0c;实现方式的使用 对象注入也可被称为对象装配&#xff0c;是把Bean对象获取出来放到某个类中。 对象注入的实现方式有3种&#xff0c;分别为属性注入&#xff0c;Setter注入和构造方法注入。 为了更好地理解对象注入的实现方式&#xff0c;搞个…

24 MFC文档串行化和单文档应用程序

文章目录 文档串行化全部代码 单文档应用程序搭建原理搭建框架Win32 过度到MFC 三部曲设置ID资源全部代码 单文档应用程序设置标题绘图 简单的管理系统部分代码 文档串行化 ui 设计 保存 void CfileDemoDlg::OnBnClickedBtnSave() {UpdateData();//CFile file(L"Demo.dat…

python+pytest接口自动化(9)-cookie绕过登录(保持登录状态)

目录 cookie工作原理 cookie绕过登录 总结 在编写接口自动化测试用例或其他脚本的过程中&#xff0c;经常会遇到需要绕过用户名/密码或验证码登录&#xff0c;去请求接口的情况&#xff0c;一是因为有时验证码会比较复杂&#xff0c;比如有些图形验证码&#xff0c;难以通过…

旅游信息推荐系统带文档springboot+vue

功能 用户注册和登录&#xff1a;用户可以注册一个账户并登录到系统中。旅游项目展示&#xff1a;系统展示各种旅游项目的信息&#xff0c;包括目的地、行程、费用等。旅游项目搜索和筛选&#xff1a;用户可以搜索和筛选旅游项目&#xff0c;根据目的地、日期、费用等条件。预…

Linux系统终端窗口ctrl+c,ctrl+z,ctrl+d的区别

时常在Linux系统上&#xff0c;执行某命令停不下来&#xff0c;就这几个ctrl组合键按来按去&#xff0c;今天稍微总结下具体差别&#xff0c;便于以后linux系统运维操作 1、ctrlc强制中断程序&#xff0c;相应进程会被杀死&#xff0c;中断进程任务无法恢复执行 2、ctrlz暂停正…

mongodb集群搭建

下载地址&#xff1a; https://www.mongodb.com/try/download/community下载mongodb-linux-x86_64-rhel70-5.0.18 搭建集群 tar -zxvf mongodb-linux-x86_64-rhel70-5.0.18.tgz mkdir -p data/dp cd mongodb-linux-x86_64-rhel70-5.0.18 mkdir -p data/db mkdir log mkdir c…

Ubuntu 23.04安装最新版本Halcon 23.05

Ubuntu 23.04安装最新版本Halcon 23.05 官网下载安装环境变量设置创建快捷方式给个最新ubuntu的镜像源地址 官网下载 去Halcon官网&#xff1a;https://www.mvtec.com/products/halcon/&#xff0c;注册或登录&#xff0c;点击Download&#xff1a; 或者进入大恒网站&#xf…

Ubuntu最新版本23.05配置Flameshot(途中解决疑难杂症)

Ubuntu最新版本23.05配置Flameshot截图软件 安装方法&#xff1a;添加Ubuntu的快捷键遇到的问题解决 安装方法&#xff1a; sudo apt install flameshot出现该页面表示成功&#xff1a; 可以直接在终端输入&#xff1a;flameshot gui flameshot gui进行截图。 添加Ubuntu的…

云计算与大数据——MPI集群配置

什么是MPI集群&#xff1f; MPI&#xff08;消息传递接口&#xff09;是一种用于编写并行程序的标准&#xff0c;它允许在多个计算节点上进行通信和协作。MPI集群配置是指在一个或多个计算节点上设置MPI环境以实现并行计算。 MPI集群配置的步骤&#xff1a; 硬件选型&#x…

三菱PLC上位机测试

利用三菱的MX Component与三菱PLC进行以太网通信&#xff0c;我们可以用官方的dll编写C#代码&#xff0c;特别简单&#xff0c;最后附上整个源码下载。 1. 安装MX Component&#xff08;必须&#xff09;和GX WORKS3&#xff08;主要是仿真用&#xff0c;实际可以不装&#xf…

空间光通信-调制解调滤波与同步

图文并茂&#xff0c;讲解电磁波传播原理_哔哩哔哩_bilibili 深入浅出空间光通信-3.调制解调滤波与同步_哔哩哔哩_bilibili 傅里叶变换这样学&#xff0c;何愁不会呢&#xff1f;直观理解傅里叶变换_哔哩哔哩_bilibili 第二十三课&#xff1a;声音编辑必看&#xff01;&…

【六袆 - windows】windows计划任务,命令行执行,开启计划任务,关闭计划任务,查询计划任务

windows计划任务 查看 Windows 自动执行的指令取消 Windows 中的计划任务启动执行计划任务 查看 Windows 自动执行的指令 您可以使用以下方法&#xff1a; 使用任务计划程序&#xff1a;任务计划程序是 Windows 内置的工具&#xff0c;可以用于创建、编辑和管理计划任务。您可…

pytest+allure运行出现乱码的解决方法

pytestallure运行出现乱码的解决方法 报错截图&#xff1a; 这是因为没有安装allure运行环境或者没有配置allure的环境变量导致&#xff0c;解决方案&#xff1a; 1.安装allure运行环境 官方下载地址&#xff1a;https://github.com/allure-framework/allure2/releases 百度…

JavaSE - 内部类

目录 final定义常量 1. 内部类 1.1 实例内部类 1.1.1 如何获取实例内部类的对象 1.1.2 实例内部类中不能有静态的成员变量 1.1.3 实例内部类方法中可以直接访问外部类中的任何成员 1&#xff09;在实例内部类方法中访问同名的成员时&#xff0c;优先访问自己的&#xff0…

nacos注册中心+Ribbon负载均衡+完成openfeign的调用

目录 1.注册中心 1.1.nacos注册中心 1.2. 微服务注册和拉取注册中心的内容 2.3.修改订单微服务的代码 3.负载均衡组件 3.1.什么是负载均衡 3.2.什么是Ribbon 3.3.Ribbon 的主要作用 3.4.Ribbon提供的负载均衡策略 4.openfeign完成服务调用 4.1.什么是OpenFeign 4.2…

5.2 Python高阶特性之---切片迭代

一、 切片 一般用于提取指定区间内的内容&#xff0c;常用于&#xff1a;str、list、tuple等类型的的局部变量&#xff0c;如下为具体案例1、 【列表切片】 res_list [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]1&#xff09; 无步长: …

C++——类的六大默认成员构造函数

文章目录 1.默认成员函数思维导图2.构造函数定义特性 2.析构函数定义特性 3.拷贝构造函数定义特性 4.赋值构造函数定义特性 5.重载取地址运算符定义特性 6.重载const取地址运算符定义特性 1.默认成员函数思维导图 2.构造函数 定义 在面向对象编程中&#xff0c;构造函数是一种…

RHCSA——Linux网络、磁盘及软件包管理

ZY目录 Linux操作系统讲解&#xff1a;一、网络管理1、NetworkManager1.1、nmtui界面&#xff1a;1.2、nmcli使用方法&#xff1a; 2、配置网络2.1、网络接口以及网络连接2.2、配置方法&#xff1a;2.3、ping命令&#xff1a;2.4、wget命令 二、磁盘管理2.1、分区得两种格式2.1…

HCIP第五次作业

配置IP地址 r1 [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.0.0.1 24 [r1-GigabitEthernet0/0/0]int lo0 [r1-LoopBack0]ip add 192.168.1.1 24 [r1-LoopBack0]int lo1 [r1-LoopBack1]ip add 10.0.0.1 24 r2 [r2]int g0/0/0 [r2-GigabitEthernet0/0/0]ip add 12.0.0.2 …