18,迭代器模式(Iterator)
18.1,问题引入_学校体系结构
- 在 组合模式 中引入了学校体系结构,并通过
List
集合对各个层级进行定义,可以很方便的对整个结构进行遍历 - 但是如果各个层级的下属部门集合不一定都是用
List
集合定义,而是通过Set
,array
或者其他自定义方式进行存储,那就没有一个统一的方式进行结构遍历 - 此时可以引入迭代器模式进行统一
18.2,基本介绍
- 迭代器模式(Iterator Pattern)是一种常用的设计模式,属于行为型模式
- 如果我们的集合是通过不同的方式实现的,如Java集合,数组或者自定义集合等,当客户需要遍历这些集合时理论上就需要使用多种遍历方式,而且还会暴露出数据结构的内部规则,此时可以使用迭代器模式进行统一处理
- 迭代器模式,提供了一种遍历集合的统一接口,用一致的方式遍历元素,不需要知道元素内部数据结构
- 迭代器模式在Java集合中应用较多
18.3,类图
Department
:基础元素类,实体类Iterator
:顶层迭代器接口,取自java.util.Iterator
,不需要自行定义,直接从JDK中取即可XXXCollegeIterator
:具体迭代器类,对应每一个需要遍历的实体集合,重写迭代器方法,进行元素发现和元素获取College
:顶层集合类接口,定义自定义集合的基本方法,并提供统一的获取迭代器方式XXXCollege
:具体集合类,重写各自的迭代器获取方式,每一个集合类对应一个迭代器类,各自独立PrintCollege
:集合类的管理类,即List<List>
,可以对集合类进行统一输出
18.4,代码实现
-
Department
:实体类package com.self.designmode.iterator; /** * 基础部门对象, 迭代器模式的基础对象 * @author PJ_ZHANG * @create 2020-12-11 17:24 **/ public class Department { private String name; private String des; public Department(String name, String des) { this.name = name; this.des = des; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDes() { return des; } public void setDes(String des) { this.des = des; } }
-
Iterator
:java.util.Iterator
类package java.util; import java.util.function.Consumer; public interface Iterator<E> { boolean hasNext(); E next(); default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> var1) { Objects.requireNonNull(var1); while(this.hasNext()) { var1.accept(this.next()); } } }
-
ComputerCollegeIterator
:计算机学院迭代器类package com.self.designmode.iterator; import java.util.Iterator; /** * 计算机学院迭代器 * @author PJ_ZHANG * @create 2020-12-11 17:25 **/ public class ComputerCollegeIterator implements Iterator { private Department[] departmentArr; private int index = 0; public ComputerCollegeIterator(Department[] departmentArr) { this.departmentArr = departmentArr; } @Override public boolean hasNext() { // 如果当前索引以后到最后了, 则条件不成立,返回false // 如果数组中有一个元素, 则index = 0 == 1 - 1 = 0, 成立, 可以取第0个 // 此处if判断不严谨, 没有加数组长度, 说明问题即可 if (index <= departmentArr.length - 1 && null != departmentArr[index]) { return true; } return false; } @Override public Object next() { // 取当前元素数据, 并推进索引位置 return departmentArr[index++]; } }
-
InfoCollegeIterator
:信息工程学院迭代器类package com.self.designmode.iterator; import java.util.Iterator; import java.util.List; /** * 信息工程学院迭代器 * @author PJ_ZHANG * @create 2020-12-11 17:25 **/ public class InfoCollegeIterator implements Iterator { private List<Department> lstDepartment; private int index = 0; public InfoCollegeIterator(List<Department> lstDepartment) { this.lstDepartment = lstDepartment; } @Override public boolean hasNext() { // 如果当前索引以后到最后了, 则条件不成立,返回false // 如果数组中有一个元素, 则index = 0 == 1 - 1 = 0, 成立, 可以取第0个 if (index <= lstDepartment.size() - 1) { return true; } return false; } @Override public Object next() { // 取当前元素数据, 并推进索引位置 return lstDepartment.get(index++); } }
-
College
:学院顶层接口package com.self.designmode.iterator; import java.util.Iterator; /** * 学校顶层接口 * @author PJ_ZHANG * @create 2020-12-11 17:30 **/ public interface College { void addDepartment(Department department); Iterator iterator(); }
-
ComputerCollege
:计算机学院package com.self.designmode.iterator; import java.util.Iterator; /** * 计算机学院 * @author PJ_ZHANG * @create 2020-12-11 17:31 **/ public class ComputerCollege implements College { // 构造学院下专业集合 private Department[] departmentArr; // 推进索引 private int index = 0; public ComputerCollege() { departmentArr = new Department[5]; } /** * 添加专业 * @param department */ @Override public void addDepartment(Department department) { departmentArr[index++] = department; } /** * 生成计算机学院遍历的迭代器,准备进行遍历 * @return */ @Override public Iterator iterator() { return new ComputerCollegeIterator(departmentArr); } }
-
InfoCollege
:信息工程学院package com.self.designmode.iterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 信息工程学院 * @author PJ_ZHANG * @create 2020-12-11 17:31 **/ public class InfoCollege implements College { // 构造学院下专业集合 private List<Department> lstDepartment; public InfoCollege() { lstDepartment = new ArrayList<>(10); } /** * 添加专业 * @param department */ @Override public void addDepartment(Department department) { lstDepartment.add(department); } /** * 生成信息工程学院遍历的迭代器,准备进行遍历 * @return */ @Override public Iterator iterator() { return new InfoCollegeIterator(lstDepartment); } }
-
PrintCollege
:学院管理类package com.self.designmode.iterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 学院遍历类 * @author PJ_ZHANG * @create 2020-12-11 17:35 **/ public class PrintCollege { private List<College> lstCollege = new ArrayList<>(10); /** * 添加学院对象 * @param college */ public void addCollege(College college) { lstCollege.add(college); } /** * 进行遍历 */ public void showCollege() { for (College college : lstCollege) { Iterator iterator = college.iterator(); showIterator(iterator); } } public void showIterator(Iterator iterator) { for (;iterator.hasNext();) { Department department = (Department) iterator.next(); System.out.println(department.getName()); } } }
-
Client
:客户端package com.self.designmode.iterator; /** * 客户端, 进行执行 * @author PJ_ZHANG * @create 2020-12-11 17:38 **/ public class Client { public static void main(String[] args) { // 总体展示类 PrintCollege printCollege = new PrintCollege(); // 构建计算机学院 ComputerCollege computerCollege = new ComputerCollege(); computerCollege.addDepartment(new Department("Java专业", "Java专业")); // 构造信息工程学院 InfoCollege infoCollege = new InfoCollege(); infoCollege.addDepartment(new Department("信息工程", "信息工程")); // 添加学院 printCollege.addCollege(computerCollege); printCollege.addCollege(infoCollege); // 展示 // 注意: 计算机学院使用数组, 信息工程学院使用的是集合 printCollege.showCollege(); } }
18.5,迭代器模式的注意事项和细节
- 提供了统一的元素遍历方式,客户端不用再考虑聚合的类型,通过统一的方式即可遍历
- 隐藏了聚合的内部结构,客户端进行遍历只能获取到迭代器,隐藏了内部构造
- 提供了一个设计思想,即一个类中只有一个引起变化的原因(单一职责原则)。在聚合类中,将迭代器分开,就是当管理对象集合和遍历对象集合分开。这样在集合改变的话,只影响聚合对象;遍历方式改变的话,只影响迭代器
- 当要展示一组相似对象,或者遍历一组相同对象时,需要使用到迭代器模式
- 缺点:每个聚合对象都需要一个迭代器,则过多的聚合对象势必面临过多的迭代器类,不方便管理。