人物:大鸟,小菜
事件:大鸟小菜去乘公交车,上车后看见售票员要求乘客进行买票,并发现售票员不管是谁,只要有对方一上车,就能准确记住并叫住他让他买票,而且不管对方什么身份,不管你是公司员工还是小偷,只要上车,就要买票,大鸟由此给小菜讲解了迭代器模式。
迭代器模式:
1.对迭代器进行简介
2.通过迭代器实现公交车买票事件
3.反向遍历,通过迭代器实现公交车买票事件
迭代器模式简介
1.概念:提供一种方法,顺序访问一个聚合对象中各个元素,而又不暴露对象的内部表示。
2.用到的场景:
(1)售票员不管是小偷还是公司员工,不管是中国人还是外国人,只要上车都要买票,也就是说当需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑迭代器模式
(2)售票员可以从车头到车尾来售票,也可以从车尾到车头来售票,当需要对聚合对象进行多种方式遍历时,可以考虑用迭代器模式
3.举例:迭代器模式是为了遍历不同的聚合对象,提供如开始,下一个,是否结束,当前哪一项等统一的接口,如很常见的for(;;)
迭代器实现
1.结构图:
2.代码实现:
Iterator类,迭代器抽象类:
public abstract class Iterator { public abstract Object first(); public abstract Object next(); public abstract boolean isDone(); public abstract Object currentItem(); }
Aggregate类,聚合抽象类:
//用于创建迭代器
public abstract class Aggregate { public abstract Iterator createIterator(); }
ConcreteIterator类,具体迭代器类:
@Data public class ConcreteIterator extends Iterator { private ConcreteAggregate aggregate; private int current = 0;
//初始化时,将具体的聚合对象传入 public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; }
//得到聚合的第一个对象 @Override public Object first() { return aggregate.getItems().get(0); }
//得到聚合的下一个对象 @Override public Object next() { Object ret = null; current++; if (current < aggregate.count()) { ret = aggregate.getItems().get(current); } return ret; } @Override public boolean isDone() { return current >= aggregate.count() ? true : false; }
//返回当前的聚合对象 @Override public Object currentItem() { return aggregate.getItems().get(current); } }
ConcreteAggregate类,具体聚合类,继承Aggregate
public class ConcreteAggregate extends Aggregate { private List<Object> items = new ArrayList<>(); @Override public Iterator createIterator() { return new ConcreteIterator(this); } public int count() { return items.size(); } public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } }
客户端代码:
@Slf4j public class IteratorClient { public static void main(String[] args) { ConcreteAggregate a = new ConcreteAggregate(); List<Object> items = new ArrayList<>(); Object a0 = "大鸟"; Object a1 = "小菜"; Object a2 = "行李"; Object a3 = "老外"; items.add(a0); items.add(a1); items.add(a2); items.add(a3); a.setItems(items); Iterator iterator = new ConcreteIterator(a); Object item = iterator.first(); while (!iterator.isDone()) { log.info(iterator.currentItem() + "请买车票"); iterator.next(); } } }
输出结果:
大鸟请买车票
小菜请买车票
行李请买车票
老外请买车票
小菜:为什么非要用Iterator抽象类呢,好像直接使用也是可以的
大鸟:那是因为你没有注意到迭代器的第二个好处 --> 当你需要对聚合对象进行多种方式遍历时,可以考虑用迭代器模式
小菜从后向前遍历版的迭代器实现
ConcreteIteratorDesc类,实现一个从后向前的迭代器:
public class ConcreteIteratorDesc extends Iterator { private ConcreteAggregate aggregate; private int current = 0; public ConcreteIteratorDesc(ConcreteAggregate aggregate) { this.aggregate = aggregate; current = aggregate.count() - 1; } @Override public Object first() { return aggregate.getItems().get(aggregate.count() - 1); } @Override public Object next() { Object ret = null; current--; if (current >= 0) { ret = aggregate.getItems().get(current); } return ret; } @Override public boolean isDone() { return current < 0 ? true : false; } @Override public Object currentItem() { return aggregate.getItems().get(current); } }
客户端:
//Iterator iterator = new ConcreteIterator(a); Iterator iterator = new ConcreteIteratorDesc(a);
输出结果如下,与之前结果相反:
老外请买车票
行李请买车票
小菜请买车票
大鸟请买车票
总体来说:迭代模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。