迭代器模式 Iterator
一. 复习java提供的迭代器
- 在import java.util.Iterator 提供了迭代器接口,该接口被其子类实现并重写抽象方法,主要关注 hashNext(), next(),remove(),方法等
- 已ArrayList集合为例,该集合继承AbstractList抽象类,在AbstractList中通过一个内部类,实现了Iterator接口,并从写了抽象方法
AbstractList源码(这就是迭代器模式)
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
分析AbstractList源码:
- 获取Iterato: 返回的是实现了Iterator接口的Itr内部类对象
- hashNext()方法: 判断的是当前下标如果不等于集合长度的话就返回true;如果等于size()时会出现两种情况,当前集合数据为空,或者当前下标的位置等于了集合总长度,如果此时根据下标值去获取集合中的元素时,会抛出空指针异常,因为"下标=size()-1";返回false
- next()方法: 首先会根据下标位置获取集合中的元素,然后将下标位置累计+1向下一个进行迭代,然后返回
- 总结: 在集合中使用Iterator迭代器时,如果需要执行next()获取数据,必须要先执行hashNext()去判断元素,并初始化下标位置,在next()获取元素时,会自动将下标加1,向下迭代,复习查看迭代器源码的原因是为了学习迭代,后面会用到,注意在哪个位置进行迭代(有的会在hasnNext()方法中迭代)
二. 迭代器模式概述
是一种行为型设计模式,提供一种方法顺序的访问容器中的各个元素,而又不需要暴露该对象的内部表示(这里的内部表示是不是可以理解为容器的类型?,例如使用数组作为容器,使用List集合作为容器,或者使用Map集合作为容器?迭代器模式是为了解决,自定义容器的时候,或者容器类型不统一的时候使用的?)
迭代器模式角色分析
- Iterator 迭代器接口import java.util.Iterator,定义了访问遍历,删除元素的抽象方法
- ConcreteIterator 具体迭代器,持有容器数据,定义了迭代需要的下标位置,实现Iterator接口,根据容器类型的不同重写抽象方法,
- Aggregate 容器接口: 存放数据的容器的抽象父接口,定义了获取迭代器的抽象方法
- ConcreteAggregate: 具体容器,实现容器父接口,编写根据数据容器获取迭代器的方法
- Element 数据父接口,与数据对象实体
三. 案例示例
案例:
遍历展示学院中的系,计算机学院的系在计算机中是以集合存放的,信息学院中的系是已数组存放的
代码示例
- 创建实体数据对象"系"对应 Element
//系
class Department{
private String name; //系的名字
private String desc; //系的描述
public Department(String name, String desc) {
super();
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;
}
}
- 创建具体迭代器一 “计算机学院迭代器"与"信息学院迭代器” 对应 ConcreteIterator,注意容器类型的不同,hashNext()方法,与next()方法的编写方式
//计算机学院,实现Iterator接口,并重写抽象方法
class ComputerCollegeIterator implements Iterator{
//1.存放数据的容器(存放者计算机学院的所有系)
public Department[] departmentArr;
//2.游标首次的位置(为迭代遍历元素提供)
public int index = 0;
//构造器对容器赋值
public ComputerCollegeIterator(Department[] departmentArr) {
this.departmentArr = departmentArr;
}
//重写hashNext()方法,获取是否有值
@Override
public boolean hasNext() {
if(index>= departmentArr.length || null == departmentArr[index]) {
return false;
}else {
return true;
}
}
//重写next方法,获取元素,并迭代游标
@Override
public Object next() {
Department department = departmentArr[index];
index +=1;
return department;
}
}
//信息学院迭代器,实现Iterator接口
class InfoCollegeIterator implements Iterator{
//系容器
public List<Department> departmentList;
//游标首次的位置
public int index = -1;
//构造器对容器数据赋值
public InfoCollegeIterator(List<Department> departmentList) {
this.departmentList = departmentList;
}
//判断是否有值,重点,如果有值,会迭代游标+1
@Override
public boolean hasNext() {
if(index >= departmentList.size()-1) {
return false;
}else {
index += 1;
return true;
}
}
//重写next()方法,直接get()根据下标位置返回
@Override
public Object next() {
return departmentList.get(index);
}
}
- 创建容器父接口对应 Aggregate,重点是获取迭代器方法
interface College{
//添加系
public void addDepartment(Department department);
//获取迭代器
public Iterator createIterator();
}
- 创建具体容器,“计算机学院”,“信息学院”,不同容器中存放数据的容器类型不同
//计算机学院
class ComputerCollege implements College{
//存放计算机系的容器是数组
public Department[] departmentArr;
//向容器中添加数据"系"的下标位置
public int numOfDepartment = 0;
//通过构造器初始化存放系的容器大小
public ComputerCollege(int size) {
departmentArr = new Department[size];
}
//想容器中添加数据(系)
@Override
public void addDepartment(Department department) {
departmentArr[numOfDepartment] = department;
numOfDepartment +=1;
}
//根据容器的不同获取对应的具体迭代器
@Override
public Iterator createIterator() {
return new ComputerCollegeIterator(departmentArr);
}
}
//信息学院
class InfoCollege implements College{
//存放计算机系的容器是数组
public List<Department> departmentList = new ArrayList<>();
//向容器中添加数据"系"的下标位置
public int numOfDepartment = 0;
@Override
public void addDepartment(Department department) {
departmentList.add(department);
numOfDepartment +=1;
}
@Override
public Iterator createIterator() {
return new InfoCollegeIterator(departmentList);
}
}
- 对应客户端的交互层(为了方便客户端调用加的,跟此处的的设计模式没有关系)
//对应客户端的交互层
class OutPutImpl{
//存放学院的容器
public List<College> collegeList;
//通过构造器初始化赋值学院
public OutPutImpl(List<College> collegeList) {
this.collegeList = collegeList;
}
//遍历输出学院,学院与学院总保存的系的信息
public void printCollege() {
Iterator<College> iterator = collegeList.iterator();
while(iterator.hasNext()) {
//拿到学院对象数据
College college = iterator.next();
printDepartment(college.createIterator());
}
}
//遍历输出指定学院中的系信息(Iterator对应的是具体学院)
public void printDepartment(Iterator iterator) {
while(iterator.hasNext()) {
Department department = (Department) iterator.next();
System.out.println(department.getName());
}
}
}
- 调用测试
public static void main(String[]args) {
//创建学院集合
List<College> collegeList = new ArrayList<College>();
//创建计算机学院
ComputerCollege computerCollege = new ComputerCollege(10);
//将计算机学院放入集合中
collegeList.add(computerCollege);
//创建"通信工程"系
Department de = new Department("通信工程","通信工程系描述");
//将"通信工程系"放入计算机学院中
computerCollege.addDepartment(de);
//创建交互层对象
OutPutImpl out = new OutPutImpl(collegeList);
//输出学院与学院中的系的信息
out.printCollege();
}
- 流程图(不是UML)