第 19 章 迭代器模式

1、学校院系展示需求

编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系。 如图:

2、传统方案解决学校院系展示需求

传统的方式的问题分析

  1. 将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的
  2. 实际上我们的要求是 : 在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系, 因此这种方案,不能很好实现的遍历的操作
  3. 假如计算机学院的院系存储在数组中,信息工程学院的院系存储在集合中,我们要怎么才能定义一个统一的规范,来遍历不同存储结构下的院系。解决方案: => 迭代器模式

3、迭代器模式基本介绍

  1. 迭代器模式(Iterator Pattern) 是常用的设计模式,属于行为型模式
  2. 如果我们的集合元素是用不同的方式实现的, 有数组,还有java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
  3. 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,对于使用者来说,不需要知道集合对象的底层表示,即: 不暴露集合的内部结构

4、迭代器模式的原理类图

  1. Iterator :迭代器接口,由 JDK 提供,该接口定义了三个用于遍历集合(数组)的方法:hasNext()next()remove()
  2. ConcreteIterator:具体的迭代器类,实现具体的迭代逻辑
  3. Aggregate:一个统一的聚合接口,将客户端和具体的 Aggregate 实现类解耦
  4. ConcreteAggreage :具体的聚合实现类,该类持有对象集合(Element),并提供一个方法,返回一个迭代器, 该迭代器可以正确遍历集合
  5. Client:客户端,通过 IteratorAggregate 依赖其对应的子类

5、迭代器模式解决学校院系展示需求

应用实例要求

编写程序展示一个学校院系结构: 需求是这样, 要在一个页面中展示出学校的院系组成, 一个学校有多个学院,一个学院有多个系


类图


代码实现

  1. Department:实体类,用于表示学院的系

    //系
    public class Department {private String name;private String desc;public Department(String name, String desc) {this.name = name;this.desc = desc;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}}
    
  2. ComputerCollegeIterator:计算机院系的迭代器,该类实现了 Iterator 接口,用于迭代计算机学院的系

    public class ComputerCollegeIterator implements Iterator {// 这里我们需要Department 是以怎样的方式存放=>数组Department[] departments;int position = 0; // 遍历的位置public ComputerCollegeIterator(Department[] departments) {this.departments = departments;}// 判断是否还有下一个元素@Overridepublic boolean hasNext() {if (position >= departments.length || departments[position] == null) {return false;} else {return true;}}@Overridepublic Object next() {Department department = departments[position];position += 1;return department;}// 删除的方法,默认空实现@Overridepublic void remove() {}}
    
  3. InfoColleageIterator:信息院系的迭代器,该类实现了 Iterator 接口,用于迭代信息学院的系

    public class InfoColleageIterator implements Iterator {List<Department> departmentList; // 信息工程学院是以List方式存放系int index = -1;// 索引public InfoColleageIterator(List<Department> departmentList) {this.departmentList = departmentList;}// 判断list中还有没有下一个元素@Overridepublic boolean hasNext() {if (index >= departmentList.size() - 1) {return false;} else {index += 1;return true;}}@Overridepublic Object next() {return departmentList.get(index);}// 空实现remove@Overridepublic void remove() {}}
    
  4. College:学院的聚合接口

    public interface College {public String getName();// 增加系的方法public void addDepartment(String name, String desc);// 返回一个迭代器,遍历public Iterator createIterator();}
    
  5. ComputerCollege:计算机学院的聚合接口实现类,该类聚合了 Department[] 数组,并提供访问 Department[] 数组的迭代器

    public class ComputerCollege implements College {Department[] departments;int numOfDepartment = 0;// 保存当前数组的对象个数public ComputerCollege() {departments = new Department[5];addDepartment("Java专业", " Java专业 ");addDepartment("PHP专业", " PHP专业 ");addDepartment("大数据专业", " 大数据专业 ");numOfDepartment = 3;}@Overridepublic String getName() {return "计算机学院";}@Overridepublic void addDepartment(String name, String desc) {Department department = new Department(name, desc);departments[numOfDepartment] = department;numOfDepartment += 1;}@Overridepublic Iterator createIterator() {return new ComputerCollegeIterator(departments);}}
    
  6. InfoCollege:信息学院的聚合接口实现类,该类聚合了 List<Department> 集合,并提供访问 List<Department> 集合的迭代器

    public class InfoCollege implements College {List<Department> departmentList;public InfoCollege() {departmentList = new ArrayList<Department>();addDepartment("信息安全专业", " 信息安全专业 ");addDepartment("网络安全专业", " 网络安全专业 ");addDepartment("服务器安全专业", " 服务器安全专业 ");}@Overridepublic String getName() {return "信息工程学院";}@Overridepublic void addDepartment(String name, String desc) {Department department = new Department(name, desc);departmentList.add(department);}@Overridepublic Iterator createIterator() {return new InfoColleageIterator(departmentList);}}
    
  7. OutPutImpl:为 Client 层提供遍历输出学院系的方法

    public class OutPutImpl {// 学院集合List<College> collegeList;public OutPutImpl(List<College> collegeList) {this.collegeList = collegeList;}// 遍历所有学院,然后调用printDepartment 输出各个学院的系public void printCollege() {// 从collegeList 取出所有学院, Java 中的 List 已经实现IteratorIterator<College> iterator = collegeList.iterator();while (iterator.hasNext()) {// 取出一个学院College college = iterator.next();System.out.println("=== " + college.getName() + "=====");printDepartment(college.createIterator()); // 得到对应迭代器}}// 输出学院的系public void printDepartment(Iterator iterator) {while (iterator.hasNext()) {Department d = (Department) iterator.next();System.out.println(d.getName());}}}
    
  8. Client:测试代码

    public class Client {public static void main(String[] args) {// 创建学院List<College> collegeList = new ArrayList<College>();ComputerCollege computerCollege = new ComputerCollege();InfoCollege infoCollege = new InfoCollege();collegeList.add(computerCollege);collegeList.add(infoCollege);OutPutImpl outPutImpl = new OutPutImpl(collegeList);outPutImpl.printCollege();}}
    

总结

院系数据真实存放在 ComputerCollegeInfoCollege 中,如果想要遍历院系,需要将院系作为参数传入 ComputerCollegeIteratorInfoColleageIterator 中,获得迭代器,进行迭代

6、JDK ArrayList 源码分析

原理类图分析

  1. ArrayList 的内部类 Itr 充当了具体实现迭代器 Iterator 的类
  2. List 就是充当了聚合接口, 含有一个 iterator() 方法, 该方法返回一个迭代器对象
  3. ArrayList 是实现聚合接口 List 的子类, 实现了 iterator() 方法
  4. Iterator 接口系统(JDK)提供
  5. 迭代器模式解决了不同集合(ArrayListLinkedList) 统一遍历问题

源码追踪

  1. Iterator 接口中定义的方法

    public interface Iterator<E> {boolean hasNext();E next();default void remove() {throw new UnsupportedOperationException("remove");}default void forEachRemaining(Consumer<? super E> action) {Objects.requireNonNull(action);while (hasNext())action.accept(next());}}
    
  2. List 接口中定义了获取 iterator 的抽象方法,即 List 充当了聚合接口

    public interface List<E> extends Collection<E> {// ...Iterator<E> iterator();// ...
    
  3. ArrayList 中实现了 iterator 方法

    public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable// ...public Iterator<E> iterator() {return new Itr();}    // ...
    
  4. Itr 实现了 Iterator 接口,为 ArrayList 的内部类,在 Itr 中,直接使用 ArrayList 中用于存放数据的 Object[] 数组,通过 size 属性标识集合元素个数

    private class Itr implements Iterator<E> {int cursor;       // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")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];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i = cursor;if (i >= size) {return;}final Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) {throw new ConcurrentModificationException();}while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);}// update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
    }
    

7、迭代器模式的注意事项

迭代器模式的注意事项和细节

优点

  1. 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
  2. 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
  3. 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
  4. 当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式

缺点

每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类(这其实也不算什么缺点啦~~~)

第 19 章 迭代器模式相关推荐

  1. 第19章 解释器模式(Interpreter Pattern)

    原文 第19章 解释器模式(Interpreter Pattern) 解释器模式 导读:解释器模式,平常用的比较的少,所以在写这个模式之前在博客园搜索了一番,看完之后那叫一个头大.篇幅很长,我鼓足了劲 ...

  2. 大话设计模式:第20章 迭代器模式

    第20章:迭代器模式 迭代器模式 迭代器模式(iterator),提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 迭代器模式适用情况: 需要访问一个聚集对象,而且不管这些对象 ...

  3. 第19章 归档模式下的数据库恢复

    1. Restore(修复)将数据文件带回到过去(备份的时间点)+Recover(恢复)恢复从备份到数据文件崩溃这段时间内所有提交的数据=>数据库的完全恢复(所有提交的数据都恢复): 1)修复损 ...

  4. 《Head First设计模式》第九章(1)迭代器模式

    迭代器模式 因为这一章涉及到两个模式,内容有点多,还有一个组合模式留到下一篇写吧. 有许多种方法可以把对象堆起来成为一个集合(collection).你可以把它们放进数组.堆栈.列表或者是散列表(Ha ...

  5. Head First设计模式读书笔记八 第九章上 迭代器模式

    之前的总结: https://blog.csdn.net/u011109881/article/details/59677544 个人觉得本章节,HeadFirst讲的没有之前看到的网站讲的清晰,至少 ...

  6. 设计模式——19.迭代器模式

    迭代器模式(Iterator) "数据结构"类模式 当一些组件在内部具有特定的数据结构,为了不让客户程序对这些数据结构产生依赖而导致破坏组件的复用性.此时,将这些特定的数据结构封装 ...

  7. Android设计模式之——迭代器模式

    一.介绍 迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一.迭代器模式算是一个比较古老的设计模式,其源于对容器的访问,比如Java中的List.Map ...

  8. 迭代器模式(实际运用比较少)

    一.迭代器模式介绍 迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一. 源于对容器的访问,比如java中的list,Map,数组等,我们知道对容器对象 ...

  9. 第 十七 章迭代器、生成器和经典协程

    当我在自己的程序中看到模式时,我认为这是一个麻烦的迹象.程序的形状应该只反映它需要解决的问题.代码中的任何其他规律性都表明,至少对我来说,我对抽象的理解还不够深--通常是我手动完成的事情,本应该通过写 ...

最新文章

  1. Mac OS 如何连接windows 文件共享
  2. 鲁迅散文——狗的驳诘
  3. 小程序上传图本地片wx.chooseImage
  4. flutter刷新页面_用Flutter实现58App的首页
  5. 如果你们都忘记了鼓励原创,那,我们来 - 2017年度原创IT博主全网评选
  6. 深入浅出Google Android这本书怎么样
  7. Ubuntu下各种服务搭建及操作技巧
  8. Python中的星号:用途及使用方法(下篇)
  9. 在线教育雪崩:藏在家长群里的“水军”消失了
  10. Java 用接口实现加减乘除计算器
  11. mysql 重启_解决MYSQL死机,定时重启MYSQL,wdcp计划任务设定方法,
  12. 公司声明:Selina伤情稳定 Hebe及Ella工作继续
  13. 关于用Unity实现校区AR导航毕业设计的建议
  14. Lammps纳米压痕接触面积—Matlab接触面积计算(两种方法)
  15. 利用计算机名称共享打印机步骤,如何连接其他电脑共享的打印机(图文教程)...
  16. git---全局设置用户名、密码、邮箱
  17. hdoj 1276 士兵队列训练问题 模拟队列
  18. 保序加密OPE 算法 BCLO09及python仿真
  19. QWS:Qt Windows System
  20. [洛谷P4158][SCOI2009]粉刷匠(动态规划)

热门文章

  1. 2021-2025年中国冻融室行业市场供需与战略研究报告
  2. Cordova用插件时注意事项,不然,插件调用不到!
  3. java中将数字颠倒的工具类,java开发中常用的数字工具类
  4. 对话阿里云李飞飞:数据库迎来开源新时代 | 《新程序员》
  5. 新一代 Windows 即将发布、GPT-3 成功商业化,这届微软 Build 大会究竟带来了什么?
  6. TCP:一个悲伤的故事
  7. 最令人讨厌的编程语言:C++ Java 上榜
  8. Java 反射机制你还不会?那怎么看 Spring 源码?
  9. 惊呆了,竟然可以用这种方式秒建 Redis 集群?
  10. 绝了!RNN 还会写藏头诗!