设计模式之迭代器模式
一、java迭代器介绍
1、迭代器接口
在jdk中,与迭代器相关的接口有两个:Iterator 与 Iterable。
Iterator:迭代器,Iterator及其子类通常是迭代器本身的结构与方法;迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到
这个对象,使用迭代器就可以遍历这个对象的内部。
Iterable:可迭代的,那些想用到迭代器功能的其它类,如AbstractList HashMap等,需要实现该接口。
1)Iterator
Java提供一个专门的迭代器<<interface>>Iterator,我们可以对某个序列实现该interface,来提供标准的Java迭代器。Iterator接口实现后的功能是“使用”一个迭代器。
Package java.util;
public interface Iterator<E> {
//判断是否存在下一个对象元素
boolean hasNext();
//获得下一个元素
E next();
//移除下一个元素
void remove();
}
2)Iterable
Iterable接口实现后的功能是“返回”一个迭代器(Iterator),我们常用的实现了该接口的子接口有: Collection<E>, Deque<E>, List<E>, Queue<E>, Set<E> 等.该接口的iterator()方
法返回一个标准的Iterator实现。
public interface Iterable<T> {
Iterator<T> iterator();
}
2、迭代器的实现
看完源码,我们来看看迭代器是如何使用的:
1) 若类A想要使用迭代器,则它的类声明部分为 class A implement Iterable
2) 在类A实现中,要实现Iterable接口中的唯一方法:Iterator<T> iterator(); 这个方法用于返回一个迭代器,即Iterator接口及其子类;
3) 在类A中,定义一个内部类S,专门用于实现Iterator接口,定制类A自已的迭代器实现。
如下:
//A实现Iterable接口
class A implement Iterable
{
//该接口返回一个Iterator对象
Iterator<T> iterator() {...}
class S implement Iterator<E>
{
//上面这个对象会有具体实现的方法
boolean hasNext() {....}
E next() {....}
void remove() {....}
}
}
下面我们来看下抽象类AbstractList的jdk源码
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { // List接口实现了Collection<E>, Iterable<E>
protected AbstractList() {
}
...
// 这里返回一个迭代器对象
public Iterator<E> iterator() {
return new Itr();
}
// Itr内部类实现迭代器
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
// 实现hasNext方法
public boolean hasNext() {
return cursor != size();
}
// 实现next方法
public E next() {
//判断是否有下一个
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
//返回下一个
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
// 实现remove方法
public void remove() {
if (lastRet == -1)
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();
}
}
}
3、小案例
//实现Iterable
class ScanAppleStore implements Iterable<String> {
ArrayList<String> appleStore = new ArrayList<String>();
//为初始appleStore赋值
ScanAppleStore() {
Collections.addAll(appleStore, "Sweet", "Sour", "Bitter", "litter Sweet", "litter Sour", "litter Bitter");
System.out.print(appleStore);
}
//重写Iterator方法
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int i = 0;
public boolean hasNext() {
if (i < appleStore.size()) {
return true;
} else {
return false;
}
}
public String next() {
return appleStore.get(i++);
}
public void remove() {
System.out.print("not defined!");
}
};
}
public Iterable<String> reverseIterator() {
return new Iterable<String>() {
public Iterator<String> iterator() {
return new Iterator<String>() {
private int i = appleStore.size() - 1;
public boolean hasNext() {
if (i > -1) {
return true;
} else {
return false;
}
}
public String next() {
return appleStore.get(i--);
}
public void remove() {
System.out.print("not defined!");
}
};
}
}; }}
测试类
public class TestIterable {
//构造函数初始化
TestIterable() {
ScanAppleStore appleTree = new ScanAppleStore();
//采用系统自带的迭代器
System.out.println("采用系统自带的迭代器iterator:");
for (String str : appleTree) {
System.out.println(str);
}
System.out.println("======================");
System.out.println("采用自己重新迭代器,让相反输出");
//采用自己重新迭代器,让相反输出
for (String str : appleTree.reverseIterator()) {
System.out.println(str);
}
}
public static void main(String[] args) {
TestIterable a = new TestIterable();
}
}
运行结果:
[Sweet, Sour, Bitter, litter Sweet, litter Sour, litter Bitter]
采用系统自带迭代器iterator:
Sweet
Sour
Bitter
litter Sweet
litter Sour
litter Bitter
======================
采用自己重新迭代器,让相反输出:
litter Bitter
litter Sour
litter Sweet
Bitter
Sour
Sweet
二、迭代器模式
1、什么是迭代器模式
提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
2、迭代器模式角色组成
迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。
具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。
具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。
3、案例解析
1)迭代器角色
public interface Iterator {
public Object next();
public boolean hasNext();
}
2)具体迭代器角色
public class ConcreteIterator implements Iterator {
private List list = new ArrayList();
private int cursor = 0;
public ConcreteIterator(List list) {
this.list = list;
}
@Override
public Object next() {
Object obj = null;
if (this.hasNext()) {
obj = this.list.get(cursor++);
}
return obj;
}
@Override
public boolean hasNext() {
if (cursor == list.size()) {
return false;
}
return true;
}
}
3)容器角色
public interface Aggregate {
public void add(Object obj);
public void remove(Object obj);
public Iterator iterator();
}
4) 具体容器角色
public class ConcreteAggregate implements Aggregate {
private List list = new ArrayList();
@Override
public void add(Object obj) {
list.add(obj);
}
@Override
public void remove(Object obj) {
list.remove(obj);
}
@Override
public Iterator iterator() {
return new ConcreteIterator(list);
}
}
测试类
public class Client {
public static void main(String[] args) {
Aggregate ag = new ConcreteAggregate();
ag.add("小明");
ag.add("小红");
ag.add("小刚");
Iterator it = ag.iterator();
while (it.hasNext()) {
String str = (String) it.next();
System.out.println(str);
}
}}
运行结果
小明
小红
小刚
4、迭代器优点和缺点
优点:
1)它支持以不同的方式遍历一个聚合对象。
2)迭代器简化了聚合类。
3)在同一个聚合上可以有多个遍历。
4)在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点:
存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。