设计模式之迭代器模式 意图 迭代器模式 (Iterator) 是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。
适用场景
当集合背后为复杂的数据结构, 且你希望对客户端隐藏其复杂性时 (出于使用便利性或安全性的考虑), 可以使用迭代器模式。
使用该模式可以减少程序中重复的遍历代码。
如果你希望代码能够遍历不同的甚至是无法预知的数据结构, 可以使用迭代器模式。
结构
结构说明
迭代器 (Iterator) 接口声明了遍历集合所需的操作: 获取下一个元素、 获取当前位置和重新开始迭代等。
具体迭代器 (Concrete Iterators) 实现遍历集合的一种特定算法。 迭代器对象必须跟踪自身遍历的进度。 这使得多个迭代器可以相互独立地遍历同一集合。
集合 (Collection) 接口声明一个或多个方法来获取与集合兼容的迭代器。 请注意, 返回方法的类型必须被声明为迭代器接口, 因此具体集合可以返回各种不同种类的迭代器。
具体集合 (Concrete Collections) 会在客户端请求迭代器时返回一个特定的具体迭代器类实体。 你可能会琢磨, 剩下的集合代码在什么地方呢? 不用担心, 它也会在同一个类中。 只是这些细节对于实际模式来说并不重要, 所以我们将其省略了而已。
客户端 (Client) 通过集合和迭代器的接口与两者进行交互。 这样一来客户端无需与具体类进行耦合, 允许同一客户端代码使用各种不同的集合和迭代器。
客户端通常不会自行创建迭代器, 而是会从集合中获取。 但在特定情况下, 客户端可以直接创建一个迭代器 (例如当客户端需要自定义特殊迭代器时)。
结构代码范式 Iterator : 定义访问元素的接口。
1 2 3 4 5 6 interface Iterator { public Object first () ; public Object next () ; public boolean isDone () ; public Object currentItem () ; }
ConcreteIterator : 实现 Iterator 接口。记录当前访问的元素在集合中的位置信息。
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 class ConcreteIterator implements Iterator { private int current = 0 ; private ConcreteAggregate aggregate; public ConcreteIterator (ConcreteAggregate aggregate) { this .aggregate = aggregate; } @Override public Object first () { return aggregate.get(0 ); } @Override public Object next () { current++; if (current < aggregate.size()) { return aggregate.get(current); } return null ; } @Override public boolean isDone () { return (current >= aggregate.size()) ? true : false ; } @Override public Object currentItem () { return aggregate.get(current); } }
Aggregate : 定义创建 Iterator 对象的接口。
1 2 3 interface Aggregate { public Iterator CreateIterator () ; }
ConcreteAggregate : 实现 Iterator 接口,返回一个合适的 ConcreteIterator 实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class ConcreteAggregate implements Aggregate { private List<Object> items = new ArrayList <Object>(); @Override public Iterator CreateIterator () { return new ConcreteIterator (this ); } public int size () { return items.size(); } public Object get (int index) { return items.get(index); } public void set (int index, Object element) { items.set(index, element); } public void add (Object element) { items.add(element); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class IteratorPattern { public static void main (String[] args) { ConcreteAggregate aggregate = new ConcreteAggregate (); aggregate.add("张三" ); aggregate.add("李四" ); aggregate.add("王五" ); aggregate.add("赵六" ); Iterator iter = new ConcreteIterator (aggregate); Object item = iter.first(); System.out.println("第一个人是:" + item); System.out.println("所有人的名单是:" ); while (!iter.isDone()) { System.out.println(iter.currentItem()); iter.next(); } } }
输出
1 2 3 4 5 6 第一个人是:张三 所有人的名单是: 张三 李四 王五 赵六
伪代码 在本例中, 迭代器 模式用于遍历一个封装了访问微信好友关系功能的特殊集合。 该集合提供使用不同方式遍历档案资料的多个迭代器。
“好友 (friends)” 迭代器可用于遍历指定档案的好友。 “同事 (colleagues)” 迭代器也提供同样的功能, 但仅包括与目标用户在同一家公司工作的好友。 这两个迭代器都实现了同一个通用接口, 客户端能在不了解认证和发送 REST 请求等实现细节的情况下获取档案。
客户端仅通过接口与集合和迭代器交互, 也就不会同具体类耦合。 如果你决定将应用连接到全新的社交网络, 只需提供新的集合和迭代器类即可, 无需修改现有代码。
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 interface SocialNetwork is method createFriendsIterator (profileId) :ProfileIterator method createCoworkersIterator (profileId) :ProfileIterator class WeChat implements SocialNetwork is method createFriendsIterator (profileId) is return new WeChatIterator (this , profileId, "friends" ) method createCoworkersIterator (profileId) is return new WeChatIterator (this , profileId, "coworkers" ) interface ProfileIterator is method getNext () :Profile method hasMore () :bool class WeChatIterator implements ProfileIterator is private field weChat: WeChat private field profileId, type: string private field currentPosition private field cache: array of Profile constructor WeChatIterator (weChat, profileId, type) is this .weChat = weChat this .profileId = profileId this .type = type private method lazyInit () is if (cache == null ) cache = weChat.socialGraphRequest(profileId, type) method getNext () is if (hasMore() ) currentPosition++ return cache[currentPosition] method hasMore () is lazyInit () return currentPosition < cache.length class SocialSpammer is method send (iterator: ProfileIterator, message: string) is while (iterator.hasMore() ) profile = iterator.getNext() System.sendEmail(profile.getEmail(), message) class Application is field network: SocialNetwork field spammer: SocialSpammer method config () is if working with WeChat this .network = new WeChat () if working with LinkedIn this .network = new LinkedIn () this .spammer = new SocialSpammer () method sendSpamToFriends (profile) is iterator = network.createFriendsIterator(profile.getId()) spammer.send(iterator, "非常重要的消息" ) method sendSpamToCoworkers (profile) is iterator = network.createCoworkersIterator(profile.getId()) spammer.send(iterator, "非常重要的消息" )
与其他模式的关系
案例 使用示例: 该模式在 Java 代码中很常见。 许多框架和程序库都会使用它来提供遍历其集合的标准方式。
下面是该模式在核心 Java 程序库中的一些示例:
识别方法: 迭代器可以通过导航方法 (例如 next
和 previous
等) 来轻松识别。 使用迭代器的客户端代码可能没有其所遍历的集合的直接访问权限。
参考资料