瑞_23种设计模式_迭代器模式

news/2024/4/30 4:28:01

文章目录

    • 1 迭代器模式(Iterator Pattern)★★★
      • 1.1 介绍
      • 1.2 概述
      • 1.3 迭代器模式的结构
      • 1.4 中介者模式的优缺点
      • 1.5 中介者模式的使用场景
    • 2 案例一
      • 2.1 需求
      • 2.2 代码实现
    • 3 案例二
      • 3.1 需求
      • 3.2 代码实现
    • 4 JDK源码解析

🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的迭代器模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识,建议阅读 《瑞_23种设计模式_概述》

本系列 - 设计模式 - 链接:《瑞_23种设计模式_概述》

⬇️本系列 - 创建型模式 - 链接🔗

  单例模式:《瑞_23种设计模式_单例模式》
  工厂模式:《瑞_23种设计模式_工厂模式》
  原型模式:《瑞_23种设计模式_原型模式》
抽象工厂模式:《瑞_23种设计模式_抽象工厂模式》
 建造者模式:《瑞_23种设计模式_建造者模式》

⬇️本系列 - 结构型模式 - 链接🔗

  代理模式:《瑞_23种设计模式_代理模式》
 适配器模式:《瑞_23种设计模式_适配器模式》
 装饰者模式:《瑞_23种设计模式_装饰者模式》
  桥接模式:《瑞_23种设计模式_桥接模式》
  外观模式:《瑞_23种设计模式_外观模式》
  组合模式:《瑞_23种设计模式_组合模式》
  享元模式:《瑞_23种设计模式_享元模式》

⬇️本系列 - 行为型模式 - 链接🔗

模板方法模式:《瑞_23种设计模式_模板方法模式》
  策略模式:《瑞_23种设计模式_策略模式》
  命令模式:《瑞_23种设计模式_命令模式》
 职责链模式:《瑞_23种设计模式_职责链模式》
  状态模式:《瑞_23种设计模式_状态模式》
 观察者模式:《瑞_23种设计模式_观察者模式》
 中介者模式:《瑞_23种设计模式_中介者模式》
 迭代器模式:《后续更新》
 访问者模式:《后续更新》
 备忘录模式:《后续更新》
 解释器模式:《后续更新》

在这里插入图片描述

1 迭代器模式(Iterator Pattern)★★★

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

  迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。

  瑞:行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
  瑞:行为型模式分为类行为模式对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性

迭代器模式属于:对象行为模式

1.1 介绍

  • 意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

  • 主要解决:遍历一个聚合对象。

  • 何时使用:多个类相互耦合,形成了网状结构。

  • 如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。

  • 关键代码:定义接口:hasNext, next。

  • 应用实例
      1️⃣ JAVA 中的 iterator

  • 优点
      1️⃣ 它支持以不同的方式遍历一个聚合对象。
      2️⃣ 迭代器简化了聚合类。
      3️⃣ 在同一个聚合上可以有多个遍历。
      4️⃣ 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

  • 缺点
      1️⃣ 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

  • 使用场景
      1️⃣ 访问一个聚合对象的内容而无须暴露它的内部表示。
      2️⃣ 需要为聚合对象提供多种遍历方式。
      3️⃣ 为遍历不同的聚合结构提供一个统一的接口。

  • 注意事项
      1️⃣ 迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

1.2 概述

定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

  迭代器模式是一种强大的设计模式,它通过将遍历逻辑封装在迭代器对象中,实现了对集合对象的统一访问和操作,从而简化了客户端代码并提高了代码的可读性和可维护性。

  在Java中,迭代器模式得到了广泛的应用。Java集合框架(Collections Framework)中的Iterator接口就是迭代器模式的一个典型实现。通过实现Iterator接口,Java集合类(如ArrayList、LinkedList等)提供了统一的遍历方式,使得客户端可以方便地访问和操作集合中的元素。

1.3 迭代器模式的结构

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

1.4 中介者模式的优缺点

优点

  • 它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持新的遍历方式。

  • 迭代器简化了聚合类。由于引入了迭代器,在原有的聚合对象中不需要再自行提供数据遍历等方法,这样可以简化聚合类的设计。

  • 在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,满足 “开闭原则” 的要求。

缺点

  • 增加了类的个数,这在一定程度上增加了系统的复杂性。

1.5 中介者模式的使用场景

  • 当需要为聚合对象提供多种遍历方式时。
  • 当需要为遍历不同的聚合结构提供一个统一的接口时。
  • 当访问一个聚合对象的内容而无须暴露其内部细节的表示时。



2 案例一

【案例】自定义迭代器

2.1 需求

  定义一个可以存储学生对象的容器对象,将遍历该容器的功能交由迭代器实现。

  类图如下:

在这里插入图片描述

2.2 代码实现

  定义迭代器接口,声明hasNext、next方法

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

  定义具体的迭代器类,重写所有的抽象方法

具体迭代器角色类(类)
import java.util.List;/*** 具体迭代器角色类** @author LiaoYuXing-Ray**/
public class StudentIteratorImpl implements StudentIterator {private final List<Student> list;private int position = 0; // 用来记录遍历时的位置public StudentIteratorImpl(List<Student> list) {this.list = list;}public boolean hasNext() {return position < list.size();}public Student next() {// 从集合中获取指定位置的元素Student currentStudent = list.get(position);position++;return currentStudent;}
}

  定义抽象容器类,包含添加元素,删除元素,获取迭代器对象的方法

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

  定义具体的容器类,重写所有的方法

具体的容器类(类)

import java.util.ArrayList;
import java.util.List;/*** 具体的容器类** @author LiaoYuXing-Ray**/
public class StudentAggregateImpl implements StudentAggregate {private final List<Student> list = new ArrayList<Student>();public void addStudent(Student stu) {list.add(stu);}public void removeStudent(Student stu) {list.remove(stu);}// 获取迭代器对象public StudentIterator getStudentIterator() {return new StudentIteratorImpl(list);}
}

  迭代器元素类

学生类(类)
/*** 学生类** @author LiaoYuXing-Ray**/
public class Student {private String name;private String number;@Overridepublic 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;}public Student(String name, String number) {this.name = name;this.number = number;}public Student() {}
}
测试类
/*** 测试类** @author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 创建聚合对象StudentAggregateImpl aggregate = new StudentAggregateImpl();// 添加元素aggregate.addStudent(new Student("张三","001"));aggregate.addStudent(new Student("李四","002"));aggregate.addStudent(new Student("王五","003"));aggregate.addStudent(new Student("赵六","004"));// 遍历聚合对象// 1.获取迭代器对象StudentIterator iterator = aggregate.getStudentIterator();// 2.遍历while(iterator.hasNext()) {// 3.获取元素Student student = iterator.next();System.out.println(student.toString());}}
}

  代码运行结果如下:

	Student{name='张三', number='001'}Student{name='李四', number='002'}Student{name='王五', number='003'}Student{name='赵六', number='004'}

3 案例二

本案例为菜鸟教程中的案例

3.1 需求

  我们将创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口。实现了 Container 接口的实体类将负责实现 Iterator 接口。

  IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names。

在这里插入图片描述

3.2 代码实现

步骤 1

  创建接口

Iterator.java
public interface Iterator {public boolean hasNext();public Object next();
}
Container.java
public interface Container {public Iterator getIterator();
}

步骤 2

  创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。

NameRepository.java
public class NameRepository implements Container {public String[] names = {"Robert" , "John" ,"Julie" , "Lora"};@Overridepublic Iterator getIterator() {return new NameIterator();}private class NameIterator implements Iterator {int index;@Overridepublic boolean hasNext() {if(index < names.length){return true;}return false;}@Overridepublic Object next() {if(this.hasNext()){return names[index++];}return null;}     }
}

步骤 3

  使用 NameRepository 来获取迭代器,并打印名字。

IteratorPatternDemo.java
public class IteratorPatternDemo {public static void main(String[] args) {NameRepository namesRepository = new NameRepository();for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){String name = (String)iter.next();System.out.println("Name : " + name);}  }
}

步骤 4

  执行程序,输出结果:

	Name : RobertName : JohnName : JulieName : Lora



4 JDK源码解析

  迭代器模式在JAVA的很多集合类中被广泛应用,接下来看看JAVA源码中是如何使用迭代器模式的。

List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); //list.iterator()方法返回的肯定是Iterator接口的子实现类对象
while (iterator.hasNext()) {System.out.println(iterator.next());
}

  看完这段代码是不是很熟悉,与我们案例一的代码实现基本类似。单列集合都使用到了迭代器,我们以ArrayList举例来说明

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

  具体看看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];}...
}

  这部分代码大致就是在 iterator 方法中返回了一个实例化的 Iterator 对象。Itr是一个内部类,它实现了 Iterator 接口并重写了其中的抽象方法。

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




本文是博主的粗浅理解,可能存在一些错误或不完善之处,如有遗漏或错误欢迎各位补充,谢谢

  如果觉得这篇文章对您有所帮助的话,请动动小手点波关注💗,你的点赞👍收藏⭐️转发🔗评论📝都是对博主最好的支持~


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

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

相关文章

爱自然生命力粤东中心家风家教高端研讨会在广东汕头盛大开启

2024年3月30日&#xff0c;爱自然生命力粤东中心家风家教高端研讨会在广东汕头金海湾大酒店隆重召开。 &#xff08;图为活动现场&#xff09; 本次由爱自然生命力体系粤东中心主办的粤东家风家教高端研讨会&#xff0c;主题为“携手校家社&#xff0c;共筑新格局”&#xff0…

Linux从入门到精通 --- 2.基本命令入门

文章目录 第二章&#xff1a;2.1 Linux的目录结构2.1.1 路径描述方式 2.2 Linux命令入门2.2.1 Linux命令基础格式2.2.2 ls命令2.2.3 ls命令的参数和选项2.2.4 ls命令选项的组合使用 2.3 目录切换相关命令2.3.1 cd切换工作目录2.3.2 pwd查看当前工作目录2.4 相对路径、绝对路径和…

微信小程序的页面交互2

一、自定义属性 &#xff08;1&#xff09;定义&#xff1a; 微信小程序中的自定义属性实际上是由data-前缀加上一个自定义属性名组成。 &#xff08;2&#xff09;如何获取自定义属性的值&#xff1f; 用到target或currentTarget对象的dataset属性可以获取数据 &#xff…

Jmeter02-1:参数化组件CVS

目录 1、Jmeter组件&#xff1a;参数化概述 1.1 是什么&#xff1f; 1.2 为什么&#xff1f; 1.3 怎么用&#xff1f; 2、Jmeter组件&#xff1a;参数化实现之CSV Data Set Config(重点中重点) 2.1 是什么&#xff1f; 2.2 为什么&#xff1f; 2.3 怎么用&#xff1f; …

C#,简单,精巧,实用的文件夹时间整理工具FolderTime

点击下载本文软件&#xff08;5积分&#xff09;&#xff1a; https://download.csdn.net/download/beijinghorn/89071073https://download.csdn.net/download/beijinghorn/89071073 百度网盘&#xff08;不需积分&#xff09;&#xff1a; https://pan.baidu.com/s/1FwCsSz…

c# wpf XmlDataProvider 简单试验

1.概要 2.代码 <Window x:Class"WpfApp2.Window12"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend…