在现实生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如“数据结构”中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方式不利于程序的扩展,如果要更换遍历方法就必须修改程序源代码,这违背了 “开闭原则”。
既然将遍历方法封装在聚合类中不可取,那么聚合类中不提供遍历方法,将遍历方法由用户自己实现是否可行呢?答案是同样不可取,因为这种方式会存在两个缺点:
暴露了聚合类的内部表示,使其数据不安全;
增加了客户的负担。
“迭代器模式
”能较好地克服以上缺点,它在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”,如 Java 中的 Collection、List、Set、Map 等都包含了迭代器。
迭代器模式的定义
迭代器(Iterator
)模式的定义
:又称游标模式
,它提供一种顺序访问集合/容器对象元素的方法,而又无须暴露集合内部表示。迭代器模式可以为不同的容器提供一致的遍历行为,而不用关心容器内容元素组成结构,属于行为型模式。
迭代器模式的结构
迭代器模式主要包含以下角色:
抽象容器(Aggregate
)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
具体容器(ConcreteAggregate
)角色:实现抽象聚合类,返回一个具体迭代器的实例。
抽象迭代器(Iterator
)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
具体迭代器(Concretelterator
)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
迭代器模式的实现
//抽象迭代器
public interface Iterator<E> {
E next();//获取下一个元素的方法
boolean hasNext();//判断是否还有下个元素的方法
}
//具体迭代器
public class ConcreteIterator<E> implements Iterator<E> {
private List<E> list;
private int cursor = 0;//游标
public ConcreteIterator(List<E> list) {
this.list = list;
}
public E next() {
return this.list.get(this.cursor ++);
}
public boolean hasNext() {
return this.cursor < this.list.size();
}
}
//抽象容器
public interface IAggregate<E> {
boolean add(E element);//添加元素
boolean remove(E element);//删除元素
Iterator<E> iterator();//迭代器
}
//具体容器
public class ConcreteAggregate<E> implements IAggregate<E> {
private List<E> list = new ArrayList<E>();
public boolean add(E element) {
return this.list.add(element);
}
public boolean remove(E element) {
return this.list.remove(element);
}
public Iterator<E> iterator() {
return new ConcreteIterator<E>(this.list);
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
//来一个容器对象
IAggregate<String> aggregate = new ConcreteAggregate<String>();
//添加元素
aggregate.add("one");
aggregate.add("two");
aggregate.add("three");
//获取容器对象迭代器
Iterator<String> iterator = aggregate.iterator();
//遍历
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
程序运行结果如下:
one
two
three
迭代器模式的应用场景
我们把多个对象聚在一起形成的总体称之为集合(Aggregate),集合对象是能够包容一组对象的容器对象。不同集合其内部元素的聚合结构可能不同,而迭代器模式屏蔽了内部元素获取细节,为外部提供了一致的元素访问行为,解耦了元素迭代与集合对象间的耦合,并且通过提供不同的迭代器,可以为同个集合对象提供不同顺序的元素访问行为,扩展了集合对象元素迭代功能,符合开闭原则。迭代器模式适用于以下场景:
1.访问一个集合对象的内容而无需暴露它的内部表示。
2.为遍历不同的集合结构提供一个统一的访问接口。
迭代器模式的优缺点
主要优点
如下:
1.多态迭代:为不同的聚合结构提供一致的遍历接口,即一个迭代接口可以访问不同的集合对象;
2.简化集合对象接口:迭代器模式将集合对象本身应该提供的元素迭代接口抽取到了迭代器中,使集合对象无需关心具体迭代行为;
3.元素迭代功能多样化:每个集合对象都可以提供一个或多个不同的迭代器,使得同种元素聚合结构可以有不同的迭代行为;
4.解耦迭代与集合:迭代器模式封装了具体的迭代算法,迭代算法的变化不会影响集合对象的架构。
其主要缺点
是:
1.增加了类的个数,这在一定程度上增加了系统的复杂性。
2.对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐。
注意
:
在日常开发中,我们几乎不会自己写个迭代器。除非我们需要定制一个自己实现的数据结构对应的迭代器,否则,开源框架提供给我们的API足够用,不必重复造轮子。