The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
迭代器模式可以让我们在不需要知道一个集合的具体实现的情况下,依次访问集合中的各个元素
it also places the task of traveral(遍历) on the iterator object, not on the aggregate, which simplifies the aggregate interface and implementation, and places the responsibility where it should be.
Design Principle: A class should have only one reason to change
UML
1 | @startuml |
ASCII 版本图示:
1 | +------------------+ +--------------------+ |
缘起
现在你是餐饮部的大老板了,上周你刚收购了两家餐厅,现在你要整合他们的业务,将他们的菜单合并以统一的用户体验,所幸,他们的底层菜品条目是一致的
1 | public class MenuItem { |
两家店铺的菜单实现代码如下
1 | // 煎饼电,通过 List 来存储菜单 |
在没有做重构的情况下,每当你想要打印所有的菜单,你就得用两个循环,分别 loop 一下这两家店的菜单, 并且更糟糕的是,下次你再收购店面,你就必须再改一次这部分代码
1 | public class LoopMenu { |
为了解决这个问题,我们新建一个 Iterator 接口来解决这个问题
1 | public interface Iterator { |
为小吃店新建一个 Iterator 实现并在小吃点的菜单中添加返回 Iterator 的方法
1 | public class DinerMenuIterator implements Iterator { |
对煎饼摊做同样的操作
1 | public class PancakeHouseMenuIterator implements Iterator { |
客户端的代码
1 | public class IteratorClient { |
其实 Java util 包下有自己的 Iterator 实现,集合类是这个设计模式的重度使用者,下面我们用官方实现替换我们自己的实现。
代码会更简单,除了在各 class 文件中引入的引用外,PancakeHouseMenuIterator 可以删除, 在 PancakeHouseMenu 的 createIterator() 直接返回 List.iterator() 即可。
为了让实现更精简,我们还可以抽象出一个 Menu 类作为基类
1 | public interface Menu { |
然后两个 Menu 实体类实现这个接口
1 | public class DinerMenu implements Menu { |
客户端中通过 Menu 基类访问
1 | public class IteratorClient { |
这样最大的好处是,客户端只和接口做交互,不需要关心具体实现,这就是传说中的 面向接口编程
时隔半个月,你又收购了一家咖啡店,是时候测试一下你的策略是否好使了。咖啡店菜单如下
1 | public class CafeMenu { |
我们按照之前的重构方案,让他实现 Menu 接口并提对应的方法实现
1 | public class CafeMenu implements Menu{ |
然后在 IteratorClient 中添加对应的调用
1 | public class IteratorClient { |
一切和预期的一样 ╮( ̄▽ ̄””)╭