迭代器模式
1、学院展示需求
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系。
【传统方式问题分析】
1)将学院看作是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的。
2)实际上我们的要求是:在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系,因此这种方案,不能很好实现遍历的操作。
3)解决方案:迭代器模式。
2、迭代器模式的基本介绍
1)迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式。
2)如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
3)迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
3、结构
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合元素以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:具体的聚合持有对象集合,并提供一个方法,返回一个迭代器。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常含有hasNext、next、remove等方法。
- 具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
4、应用实例代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
| public class Department { private String name; private String desc; public Department(String name, String desc) { this.name = name; this.desc = desc; } getter、setter }
public class ComputerCollegeIterator implements Iterator { private Department[] departments; private int position = 0; public ComputerCollegeIterator(Department[] departments) { this.departments = departments; } @Override public boolean hasNext() { return position != departments.length; } @Override public Object next() { Department department = departments[position]; position++; return department; } public void remove() { } }
public class InfoCollegeIterator implements Iterator {
private List<Department> departments; int index = 0; public InfoCollegeIterator(List departments) { this.departments = departments; } @Override public boolean hasNext() { return index != departments.size(); } @Override public Object next() { Department department = departments.get(index); index++; return department; } public void remove() { } }
public interface College { String getName(); void addDepartment(String name, String desc); Iterator createIterator(); }
public class ComputerCollege implements College { private Department[] departments; private int numOfDepartment = 0; public ComputerCollege() { departments = new Department[5]; addDepartment("Java专业", "Java专业"); addDepartment("PHP专业", "PHP专业"); addDepartment("大数据专业", "大数据专业"); } @Override public String getName() { return "计算机学院"; } @Override public void addDepartment(String name, String desc) { Department department = new Department(name, desc); departments[numOfDepartment] = department; numOfDepartment++; } @Override public Iterator createIterator() { return new ComputerCollegeIterator(departments); } }
public class InfoCollege implements College { private List<Department> departments; private int numOfDepartment = 0; public InfoCollege() { departments = new ArrayList(); addDepartment("信息安全专业", "信息安全专业"); addDepartment("网络安全", "网络安全"); addDepartment("服务器安全", "服务器安全"); } @Override public String getName() { return "信息工程学院"; } @Override public void addDepartment(String name, String desc) { Department department = new Department(name, desc); departments.add(department); numOfDepartment++; } @Override public Iterator createIterator() { return new InfoCollegeIterator(departments); } }
public class OutputImpl { List<College> collegeList; public OutputImpl(List<College> collegeList) { this.collegeList = collegeList; } public void printCollege() { collegeList.forEach(college -> { System.out.println("====" + college.getName() + "===="); Iterator iterator = college.createIterator(); printDepartment(iterator); }); } public void printDepartment(Iterator iterator) { while(iterator.hasNext()) { Department d = (Department)iterator.next(); System.out.println(d.getName()); } } }
public class Client { public static void main(String[] args) { List<College> collegeList = new ArrayList(); ComputerCollege computerCollge = new ComputerCollege(); InfoCollege infoCollege = new InfoCollege(); collegeList.add(computerCollge); collegeList.add(infoCollege); OutputImpl op = new OutputImpl(collegeList); op.printCollege(); } }
|
5、迭代器模式的注意事项
【优点】
1)提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。同时它支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。在迭代器模式中只需要用一个不同的迭代器来替换原有迭代器即可改变遍历算法,我们也可以自己定义迭代器的子类以支持新的遍历方式。
2)隐藏了聚合的内部结构,客户端要遍历聚合的时候只需取到迭代器,而不会知道聚合的具体组成。
3)提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一职责原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
4)当要展示一组相似对象,或者遍历一组相同对象时,适合使用迭代器模式。
5)在迭代器模式中,由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无需修改原有代码,满足”开闭原则”的要求。
【缺点】
1)每个聚合对象都要一个迭代器,会生成多个迭代器,不好管理。
【使用场景】
1)当需要为聚合对象提供多种遍历方式时。
2)当需要为遍历不同的聚合结构提供一个统一的接口时。
3)当访问一个聚合对象的内容而无须暴露其内部细节的表示时。
注意:
当我们在使用Java开发的时候,想使用迭代器模式的话,只要让我们自己定义的容器类实现java.util.Iterable并实现其中的iterator()方法使其返回一个java.util.Iterator的实现类就可以的。
6、迭代器模式在JDK-ArrayList集合应用的源码分析
1)JDK的ArrayList集合中就使用了迭代器模式。
2)代码分析。
- 内部类Itr充当具体实现迭代器Iterator的类,作为ArrayList内部类。
- List就是充当了聚合接口,含有一个iterator()方法,返回一个迭代器对象。
- ArrayList是实现聚合接口List的子类,实现了iterator()。
- Iterator接口系统提供。
- 迭代器模式解决了不同集合(ArrayList,LinkedList)统一遍历问题。