第 19 章 迭代器模式
第 19 章 迭代器模式
1、学校院系展示需求
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系。 如图:
2、传统方案解决学校院系展示需求
传统的方式的问题分析
- 将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的
- 实际上我们的要求是 : 在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系, 因此这种方案,不能很好实现的遍历的操作
- 假如计算机学院的院系存储在数组中,信息工程学院的院系存储在集合中,我们要怎么才能定义一个统一的规范,来遍历不同存储结构下的院系。解决方案: => 迭代器模式
3、迭代器模式基本介绍
- 迭代器模式(
Iterator Pattern
) 是常用的设计模式,属于行为型模式 - 如果我们的集合元素是用不同的方式实现的, 有数组,还有
java
的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。 - 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,对于使用者来说,不需要知道集合对象的底层表示,即: 不暴露集合的内部结构
4、迭代器模式的原理类图
Iterator
:迭代器接口,由JDK
提供,该接口定义了三个用于遍历集合(数组)的方法:hasNext()
、next()
、remove()
ConcreteIterator
:具体的迭代器类,实现具体的迭代逻辑Aggregate
:一个统一的聚合接口,将客户端和具体的Aggregate
实现类解耦ConcreteAggreage
:具体的聚合实现类,该类持有对象集合(Element
),并提供一个方法,返回一个迭代器, 该迭代器可以正确遍历集合Client
:客户端,通过Iterator
和Aggregate
依赖其对应的子类
5、迭代器模式解决学校院系展示需求
应用实例要求
编写程序展示一个学校院系结构: 需求是这样, 要在一个页面中展示出学校的院系组成, 一个学校有多个学院,一个学院有多个系
类图
代码实现
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;}}
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() {}}
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() {}}
College
:学院的聚合接口public interface College {public String getName();// 增加系的方法public void addDepartment(String name, String desc);// 返回一个迭代器,遍历public Iterator createIterator();}
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);}}
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);}}
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());}}}
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();}}
总结
院系数据真实存放在 ComputerCollege
和 InfoCollege
中,如果想要遍历院系,需要将院系作为参数传入 ComputerCollegeIterator
和 InfoColleageIterator
中,获得迭代器,进行迭代
6、JDK ArrayList 源码分析
原理类图分析
ArrayList
的内部类Itr
充当了具体实现迭代器Iterator
的类List
就是充当了聚合接口, 含有一个iterator()
方法, 该方法返回一个迭代器对象ArrayList
是实现聚合接口List
的子类, 实现了iterator()
方法Iterator
接口系统(JDK
)提供- 迭代器模式解决了不同集合(
ArrayList
,LinkedList
) 统一遍历问题
源码追踪
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());}}
在
List
接口中定义了获取iterator
的抽象方法,即List
充当了聚合接口public interface List<E> extends Collection<E> {// ...Iterator<E> iterator();// ...
在
ArrayList
中实现了iterator
方法public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable// ...public Iterator<E> iterator() {return new Itr();} // ...
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、迭代器模式的注意事项
迭代器模式的注意事项和细节
优点
- 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
- 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
- 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
- 当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式
缺点
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类(这其实也不算什么缺点啦~~~)
第 19 章 迭代器模式相关推荐
- 第19章 解释器模式(Interpreter Pattern)
原文 第19章 解释器模式(Interpreter Pattern) 解释器模式 导读:解释器模式,平常用的比较的少,所以在写这个模式之前在博客园搜索了一番,看完之后那叫一个头大.篇幅很长,我鼓足了劲 ...
- 大话设计模式:第20章 迭代器模式
第20章:迭代器模式 迭代器模式 迭代器模式(iterator),提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 迭代器模式适用情况: 需要访问一个聚集对象,而且不管这些对象 ...
- 第19章 归档模式下的数据库恢复
1. Restore(修复)将数据文件带回到过去(备份的时间点)+Recover(恢复)恢复从备份到数据文件崩溃这段时间内所有提交的数据=>数据库的完全恢复(所有提交的数据都恢复): 1)修复损 ...
- 《Head First设计模式》第九章(1)迭代器模式
迭代器模式 因为这一章涉及到两个模式,内容有点多,还有一个组合模式留到下一篇写吧. 有许多种方法可以把对象堆起来成为一个集合(collection).你可以把它们放进数组.堆栈.列表或者是散列表(Ha ...
- Head First设计模式读书笔记八 第九章上 迭代器模式
之前的总结: https://blog.csdn.net/u011109881/article/details/59677544 个人觉得本章节,HeadFirst讲的没有之前看到的网站讲的清晰,至少 ...
- 设计模式——19.迭代器模式
迭代器模式(Iterator) "数据结构"类模式 当一些组件在内部具有特定的数据结构,为了不让客户程序对这些数据结构产生依赖而导致破坏组件的复用性.此时,将这些特定的数据结构封装 ...
- Android设计模式之——迭代器模式
一.介绍 迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一.迭代器模式算是一个比较古老的设计模式,其源于对容器的访问,比如Java中的List.Map ...
- 迭代器模式(实际运用比较少)
一.迭代器模式介绍 迭代器模式(Iterator Pattern)又称为游标(Cursor)模式,是行为型设计模式之一. 源于对容器的访问,比如java中的list,Map,数组等,我们知道对容器对象 ...
- 第 十七 章迭代器、生成器和经典协程
当我在自己的程序中看到模式时,我认为这是一个麻烦的迹象.程序的形状应该只反映它需要解决的问题.代码中的任何其他规律性都表明,至少对我来说,我对抽象的理解还不够深--通常是我手动完成的事情,本应该通过写 ...
最新文章
- Mac OS 如何连接windows 文件共享
- 鲁迅散文——狗的驳诘
- 小程序上传图本地片wx.chooseImage
- flutter刷新页面_用Flutter实现58App的首页
- 如果你们都忘记了鼓励原创,那,我们来 - 2017年度原创IT博主全网评选
- 深入浅出Google Android这本书怎么样
- Ubuntu下各种服务搭建及操作技巧
- Python中的星号:用途及使用方法(下篇)
- 在线教育雪崩:藏在家长群里的“水军”消失了
- Java 用接口实现加减乘除计算器
- mysql 重启_解决MYSQL死机,定时重启MYSQL,wdcp计划任务设定方法,
- 公司声明:Selina伤情稳定 Hebe及Ella工作继续
- 关于用Unity实现校区AR导航毕业设计的建议
- Lammps纳米压痕接触面积—Matlab接触面积计算(两种方法)
- 利用计算机名称共享打印机步骤,如何连接其他电脑共享的打印机(图文教程)...
- git---全局设置用户名、密码、邮箱
- hdoj 1276 士兵队列训练问题 模拟队列
- 保序加密OPE 算法 BCLO09及python仿真
- QWS:Qt Windows System
- [洛谷P4158][SCOI2009]粉刷匠(动态规划)