文章目录
1. 模式引出–打印需求
系统需要几个人员的集合类,类中底层实现有使用数组,列表,或者是集合,现在需要编写程序,可以遍历所有人员。
- 有一个
ArrayPeoples
类和ListPeoples
类,ArrayPeoples
类中People
的集合为数组、ListPeoples
类中People
的集合为列表 People
类为集合元素- 需要一起遍历
ArrayPeoples
类和ListPeoples
类中的集合
1.1 传统方案
-
可以在所有类的外部获取集合后判断类型然后遍历
-
可以在类内部定义一个遍历方法,提供给外部调用
1.2 传统的方式的问题分析
- 每个人员类中的方法不一定相同,不能做到用统一的方式遍历有数据
- 调用麻烦,实现也麻烦
- 解决方案:迭代器模式
2. 迭代器模式基本介绍
-
迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式
-
如果我们的集合元素是用不同的方式实现的,有数组,还有java的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
-
迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
2.1 迭代器模式的原理类图
对原理类图的说明即(迭代器模式的角色及职责)
- Iterator :迭代器接口, 是系统提供,含义hastNext, next, remove
- ConcreteIterator :具体的迭代器类,管理迭代
- Aggregate :-个统-的聚合聚合接口,将客户端和具体聚合解耦
- Concretelggreage :具体的聚合持有对象集合
3. 方案修改
UML类图
Iterator.java
// java自带,无需创建
Peoples.java
// 聚合对象的接口
public interface Peoples {
Iterator<Peoples> getIterator();
}
People.java
// 集合元素
public class People {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "People [name=" + name + ", age=" + age + "]";
}
public People(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
ArrayPeoples.java
// 具体聚合类
public class ArrayPeoples implements Peoples{
private People[] peoples = new People[10];
public ArrayPeoples() {
for (int i = 0; i < 5; i++) {
peoples[i] = new People("echoArray" + i, i * i);
}
}
public Iterator getIterator() {
return new ArrayIterator(peoples);
}
}
ListPeoples.java
// 具体聚合类
public class ListPeoples implements Peoples{
private List<People> peoples = new ArrayList<People>();
public ListPeoples() {
peoples.add(new People("echolist", 1));
peoples.add(new People("echolist", 2));
peoples.add(new People("echolist", 3));
peoples.add(new People("echolist", 4));
}
public Iterator getIterator() {
return new ListIterator(peoples);
}
}
ListIterator.java
// 具体迭代器
public class ListIterator implements Iterator<People> {
private List<People> peoples;
private int foot = 0;
public ListIterator(List<People> peoples) {
this.peoples = peoples;
}
@Override
public boolean hasNext() {
return foot < peoples.size();
}
@Override
public People next() {
People people = peoples.get(foot);
foot++;
return people;
}
}
ArrayIterator.java
// 具体迭代器
public class ArrayIterator implements Iterator<People> {
private People[] peoples;
private int foot = 0;
public ArrayIterator(People[] peoples) {
this.peoples = peoples;
}
@Override
public boolean hasNext() {
return foot < peoples.length && peoples[foot] != null;
}
@Override
public People next() {
People people = peoples[foot];
foot++;
return people;
}
}
PrintPeoples.java
// 遍历管理类
public class PrintPeoples {
private List<Peoples> list = new ArrayList<Peoples>();
public void addPeopels(Peoples p) {
list.add(p);
}
public void print() {
Iterator<Peoples> iterator = list.iterator();
while (iterator.hasNext()) {
Peoples peoples = iterator.next();
print(peoples);
}
}
public void print(Peoples peoples) {
Iterator<Peoples> iterator = peoples.getIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
测试Main.java
public class Main {
public static void main(String[] args) {
ArrayPeoples arrayPeoples = new ArrayPeoples();
ListPeoples listPeoples = new ListPeoples();
PrintPeoples printPeoples = new PrintPeoples();
printPeoples.addPeopels(arrayPeoples);
printPeoples.addPeopels(listPeoples);
printPeoples.print();
}
}
输出结果
4. 迭代器模式在JDK1.8-ArrayList集合中的应用
在JDK1.8的ArrayList
源码中,可以看到ArrayList
这个类实现的接口中有一个叫List
的接口
public class ArrayList<E> ...
implements List<E>, ...
...
追到List
接口中瞧一瞧
public interface List<E> extends Collection<E> {
...
Iterator<E> iterator();
...
}
可以发现其中定义了一个Iterator<E> iterator()
的方法,该方法返回一个迭代器
回到ArrayList
类中,可以看到iterator()
方法得到了实现的
public class ArrayList<E> ...
implements List<E>, ...
{
...
public Iterator<E> iterator() {
return new Itr();
}
...
}
可以看出,ArrayList
的获取迭代器方法返回一个Itr
对象,继续追Itr
的位置
public class ArrayList<E> ...
implements List<E>, ...
...
private class Itr implements Iterator<E> {
...
}
...
}
可以看出该对象实现了Iterator
的接口,即是一个具体的迭代器,由于该类是定义为Arraylist
的内部类,所以ArrayList
存储的数据可以共享,该迭代器可以直接拿到ArrayList
的数据进行遍历操作
public class ArrayList<E> ...
implements List<E>, ...
...
transient Object[] elementData; // 存储的数据
...
}
可以看出,ArrayList
类似于上例的聚合类,包含了需要遍历的数据,实现了获取迭代器接口的方法
而Itr
类则类似于上例的具体迭代器类,实现了Iterator
接口,利用ArrayList
类中的数据进行遍历操作
4.1 总结分析
- 内部类Itr 充当具体实现迭代器Iterator 的类, 作为ArrayList 内部类
- List 就是充当了聚合接口,含有一个iterator() 方法,返回一个迭代器对象
- ArrayList 是实现聚合接口List 的子类,实现了iterator()
- Iterator 接口系统提供
- 迭代器模式解决了 不同集合(ArrayList ,LinkedList) 统一遍历问题
5. 迭代器模式的注意事项和细节
5.1 优点
-
提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
-
隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
-
提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
-
当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式
5.2 缺点
- 每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类