迭代器模式是一种行为设计模式,可以在不暴露底层实现(列表、栈或树等)的情况下,遍历一个聚合对象中所有的元素。
Iterator is a behavior design pattern that can traverse all elements of an aggregate object
without exposing the internal implementation (list, stack, tree, etc.).
结构设计
迭代器模式包含如下角色:
Iterator,迭代器基类,声明遍历聚合对象所需的操作:获取下一个元素、获取当前位置、下一个元素是否存在等。
ConcreteIterator,迭代器实现类,实现遍历聚合对象的算法。
Aggregate,聚合基类,声明一个获取迭代器的接口。
ConcreteAggregate,具体聚合实现类,实现获取一个迭代器的接口并返回一个具体迭代器实例。
Client,客户端,通过聚合基类和迭代器基类的接口与两者进行交互。
迭代器模式类图表示如下:
伪代码实现
接下来将使用代码介绍下迭代器模式的实现。
// 1、聚合接口,声明一个获取迭代器的接口,以及元素添加及删除接口
public interface IAggregate {
IIterator createIterator();
void append(Object element);
void removeLast();
}
//2、具体聚合实现类,获取一个迭代器的接口,并实现元素添加及删除接口,这里使用数组存储元素
public class ConcreteAggregate implements IAggregate {
private String[] elements;
private int cursor = -1;
public ConcreteAggregate(int size) {
elements = new String[size];
}
@Override
public void append(Object element) {
cursor++;
elements[cursor] = (String) element;
}
@Override
public void removeLast() {
elements[cursor] = "";
cursor--;
}
public int getCursor() {
return this.cursor;
}
public String[] getElements() {
return this.elements;
}
@Override
public IIterator createIterator() {
return new ConcreteIterator(this);
}
}
// 3、迭代器接口,声明遍历聚合对象所需的操作:获取下一个元素、获取当前位置、下一个元素是否存在等
public interface IIterator {
Object first();
Object next();
boolean hasNext();
Object currentItem();
}
// 4、迭代器实现类,实现遍历聚合对象的算法,及其他已声明接口
public class ConcreteIterator implements IIterator {
private ConcreteAggregate aggregate;
private int index;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
this.index = 0;
}
@Override
public Object first() {
String[] elements = aggregate.getElements();
return elements[0];
}
@Override
public Object next() {
int cursor = aggregate.getCursor();
if (cursor < 0 || index > cursor) {
return null;
}
String[] elements = aggregate.getElements();
return elements[index++];
}
@Override
public boolean hasNext() {
int cursor = aggregate.getCursor();
if (cursor < 0 || index > cursor) {
return false;
}
return true;
}
@Override
public Object currentItem() {
int cursor = aggregate.getCursor();
if (cursor < 0 || index > cursor) {
return null;
}
String[] elements = aggregate.getElements();
return elements[index];
}
}
// 5、客户端
public class IteratorClient {
public void test() {
// (1) 创建迭代对象实例
IAggregate aggregate = new ConcreteAggregate(10);
// (2) 增删元素
aggregate.append("hello");
aggregate.append("world");
aggregate.append("foo");
aggregate.removeLast();
// (3) 获取迭代器实例
IIterator iterator = aggregate.createIterator();
// (4) 执行遍历操作
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
适用场景
在以下情况下可以考虑使用迭代器模式:
(1) 当聚合对象的数据结构较复杂,且希望对客户端隐藏其复杂性时(出于易用性或安全性考虑),可考虑使用迭代器模式。迭代器封装了与复杂数据结构进行交互的细节,为客户端提供多个访问集合元素的简单方法。
这种方式不仅对客户端来说非常方便,而且能避免客户端在直接与集合交互时执行错误或有害的操作,从而起到保护集合的作用。
(2) 使用该模式可以减少程序中重复的遍历代码。重要迭代算法的代码往往体积非常庞大。当这些代码被放置在程序业务逻辑中时,它会让原始代码的职责模糊不清,降低其可维护性。因此,
将遍历代码移到特定的迭代器中可使程序代码更加精炼和简洁。
(3) 如果希望代码能够遍历不同的甚至是无法预知的数据结构,可考虑使用迭代器模式。该模式为集合和迭代器提供了一些通用接口。如果在代码中使用了这些接口,那么将其他实现了这些接口的集合和迭代器传递给它时,
它仍将可以正常运行。
优缺点
迭代器模式有以下优点:
(1) 符合单一职责原则。通过将体积庞大的遍历算法代码抽取为独立的类,可对客户端代码和集合进行整理。
(2) 符合开闭原则。可实现新型的集合和迭代器并将其传递给现有代码,无需修改现有代码。
(3) 可以并行遍历同一集合,因为每个迭代器对象都包含其自身的遍历状态。
但是该模式也存在以下缺点:
(1) 如果只与简单的集合进行交互,应用该模式可能会矫枉过正。
(2) 对于某些特殊集合,使用迭代器可能比直接遍历的效率低。
(3) 增加了系统的复杂性。因为迭代器模式将存储数据和遍历数据的职责分离,增加了新的聚合类需要对应增加新的迭代器类,增加了系统的复杂性。
参考
《设计模式 可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著, 李英军, 马晓星等译
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/mediator.html 迭代器模式
https://refactoringguru.cn/design-patterns/mediator 迭代器模式
https://www.runoob.com/design-pattern/mediator-pattern.html 迭代器模式
https://www.cnblogs.com/adamjwh/p/10959987.html 简说设计模式——迭代器模式