设计模式之迭代器模式(Iterator Pattern)
来源:互联网 发布:淘宝白色外套 编辑:程序博客网 时间:2024/06/06 01:20
这篇博客,我们要详细讲解的是迭代器模式(Iterator Pattern),将要讲解的内容有:迭代器模式的定义,作用,详细设计分析等方面。
一、Pattern name
迭代器模式(Iterator Pattern) : 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。——《设计模式 可复用面向对象软件的基础》
二、Problem
在我们实际编程的过程中,经常会遇到下面这种情况:
当我们需要遍历某个集合的时候,常常调用某个类的一个方法,返回一个集合类型的数据,如下:
private ArrayList<Book> bookList = new ArrayList<Book>();public ArrayList<Book> getBookList(){ return bookList;}
然后,再依据调用方法返回的ArrayList类型的bookList进行遍历操作。但是,这种方式将底层数据的实现方式和数据结构暴露出来,如果未来有一天想要改变底层数据结构,换为数组或者其他集合类进行实现,那么原来调用这个方法以实现遍历的那个地方就会报错。
那么,我们如何设计,才能消除以后可能发生的底层数据结构变化对整个程序的影响呢?如何设计,才能不把底层实现的数据结构暴露出来呢?这就要用到迭代器模式(Iterator Pattern)。
三、Solution
首先,我们来看一下,迭代器模式的UML类图结构:
上图是最基本,最简单情况的类图,从图中右下角处的Client Code我们可以看出,Client在需要遍历目标集合的时候,无需知道具体是用哪种数据结构实现的,它只需要通过接口Aggregate,获取一个实现了这个接口的类的对象,并调用createIterator()方法,就会获得目标集合的一个迭代器(Iterator),而这个迭代器提供了first(),next(),isDone(),currentItem()等方法,Client通过这些方法就可以成功完成对目标集合的遍历操作。
此时,如果我们想改变集合的底层实现的数据结构类型:
那么直接替换掉ConcreteAggregate就可以了,当然了,从图中我们可以看出ConcreteAggregate和ConcreteIterator耦合程度很严重,所以在更换ConcreteAggregate的时候,很可能也需要适当调整ConcreteIterator的实现代码,甚至是需要重新编写ConcreteIterator的代码。
如果我们想要增加一种底层实现的数据结构类型:
那么可以增加一个ConcreteAggregate2,然后同样实现Aggregate抽象接口方法,然后同样由于ConcreteAggregate和ConcreteIterator耦合度很严重,很有可能需要增加一个全新的ConcreteIterator的实现类,但是实现的遍历方式依旧和原来相同。所以很有可能会出现如下所示的变化:
你可能会想,我只是增加了一个底层数据结构类型,但是遍历策略没有发生改变,可不可以通过某种巧妙的设计,不用改变右边的Iterator实现类,就可以实现数据结构类型的增加呢?
其实,我在学习的时候,也产生了这样的疑问,经过我查阅资料以及分析讨论,我觉得答案是:不一定。因为不同的底层数据结构类型之间,有的差异很小,有的差异很大。对于差异很小的,我们只要提出一个抽象父类或接口,比如图中的List,我们把它改为一个抽象类或接口,其中定义了一些ListIterator实现需要用到的方法,然后再创建两个不同的实现List接口的实现类或List抽象类的继承子类ArrayList和LinkedList(或者是MusicList和MovieList等),这样虽然将底层数据结构类型在原来的ArrayList的基础上增加了一种新的实现方式:LinkedList,但是此时的遍历策略并不需要做出任何改变,只要新增加的数据结构类型实现了List中定义的方法,那就可以很容易做到和ListIterator完美结合。
但是我们要注意,如果新增加的数据结构类型与原有的数据结构类型相差太多,无法实现父类或接口(List)定义的方法,那么就必须增加一个Iterator的实现类,虽然实现的遍历策略是相同的,没有发生变化。
如果我们想要改变现有的遍历策略
那么可以改变原有的ConcreteIterator的实现类,来实现新的遍历方式,当然了这个实现类是在具体制定的ConcreteAggregate的基础上完成的,受到ConcreteAggregate的影响。
如果我们想要增加一种遍历策略:
那么可以增加一个ConcreteIterator的实现类,来实现新的遍历方式,当然了这个实现类是在具体制定的ConcreteAggregate的基础上完成的,受到ConcreteAggregate的影响。
四、Consequences
当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。当你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。
迭代器模式作用:
访问一个聚合对象的内容而无需暴露它的内部表示。
支持对聚合对象的多种遍历。
为遍历不同的聚合结构提供一个统一的接口。
它支持以不同的方式遍历一个聚合。
迭代器简化了聚合的接口。
在同一个聚合上可以有多个遍历。
五、迭代器模式的典型应用
其实,迭代器模式在很多高级语言中都有体现,甚至有完整全套的包装实现。在Java中,就有很多地方应用了迭代器模式。我们来举一个例子(对Java源码进行了适当的修改):
迭代接口:Iterator接口
public interface Iterator{ //判断是否存在下一个元素 public abstract boolean hasNext(); //返回下一个可用的元素 public abstract Object next(); //移除当前元素 public abstract void remove();}
容器接口:List接口(相当于Aggregate),定义了iterator()方法(相当于createIterator)
public interface List{ ... //取得对所有元素的遍历。可以通过Iterator提供的方法遍历集合的元素 public abstract Iterator iterator(); ...}
容器接口List的实现类ArrayList(相当于ConcreteAggregate)
public class ArrayList implements List { ... //负责创建具体迭代器角色的工厂方法 public Iterator iterator() { //把遍历委让给Iterator的实现类Itr。 return new Itr(); } ...}
迭代接口Iterator的实现类
private class Itr implements Iterator { ... }
六、常见疑问解答及其他
疑问1:可能有的人会有这样的疑问,为什么不设计成这样:
在Client中:
Aggregate a = new ConcreteAggregate();Iterator i = new ConcreteIterator(a);
通过这种方式,就可以愉快地在Client中任意组合不同的集合实现类和不同的遍历策略类,如果有三种集合实现类,有两种遍历策略类,就可以实现6种巧妙组合。多完美,为什么不这样做呢?
答案是这样的:如果这样做呢,一,Client需要知道Aggregate,ConcreteAggregate,Iterator,ConcreteIterator,对这四个都会产生相应的关联关系,增加了整个系统的关系复杂度。二,也是最重要的,如果把集合类和遍历策略的匹配放到Client中,那么Client必须知道,每个遍历策略具体是什么?而且,它需要准确地知道哪个集合类可以和哪个遍历策略类组合,哪个集合类不能和哪个策略类组合。因为我们不得不承认,并不是每个遍历策略类在所有的集合类上都是可行的。而且,要Client来负责匹配分析,几个类之间的关系,特别是和Client之间的关系会非常复杂,耦合度会非常高。
疑问2:如何构建一个健壮的迭代器
所谓健壮的迭代器是指:能够保证插入和删除操作不会干扰遍历,且不需拷贝该聚合。
我们知道在遍历一个聚合的同时更改这个聚合可能是危险的,如果在遍历聚合的时候增加或删除该聚合元素,可能会导致两次访问同一个元素或者遗漏掉某个元素。一个简单的解决方法是拷贝该集合,并对该拷贝实施遍历,但一般来说这样做代价太高。所以,我们需要努力构造一个健壮的迭代器。
当然了,有许多方法来实现健壮的迭代器,其中大多数需要向这个聚合注册该迭代器。当插入或删除元素时,该聚合要么调整迭代器的内部状态,要么在内部的维护额外的信息以保证正确的遍历。
七、总结
当然了,迭代器模式的思想博大精深。我们需要学习和分析的绝不是仅仅上面讨论的这些,除此之外,还有很多很多。如果你有新的见解,不同的分析,欢迎大家一起讨论,一起进步。
- 设计模式之-迭代器(Iterator pattern)
- 设计模式之迭代器模式--- Pattern Iterator
- 设计模式之九:迭代器模式(Iterator Pattern)
- C#设计模式之迭代器模式(Iterator Pattern)
- 设计模式之迭代器模式(Iterator Pattern)
- 设计模式总结之Iterator Pattern(迭代器模式)
- Net设计模式实例之迭代器模式(Iterator Pattern)
- 【23种设计模式】之 迭代器模式(Iterator Pattern)
- 【设计模式】迭代器模式(Iterator Pattern)
- 设计模式之迭代器(Iterator Pattern)-笔记
- Iterator Pattern--迭代器设计模式
- 设计模式(C#)之迭代器模式(Iterator Pattern)
- 设计模式(C#)之迭代器模式(Iterator Pattern)
- Php设计模式之【迭代器模式Iterator Pattern】
- JAVA设计模式之 迭代器模式【Iterator Pattern】
- 设计模式(行为型)之迭代器模式(Iterator Pattern)
- 设计模式拾荒之迭代器模式 ( Iterator Pattern )
- 设计模式21:Iterator Pattern (迭代器模式)
- 使用FOR循环语句在屏幕上输出一个由星号组成的直角三角形
- 【学习笔记】uiview点击(手势点击tap)
- iOS中的富文本技术(2)-CoreText框架
- 黑马学员《IO(字符流)》
- mysql修改字段值
- 设计模式之迭代器模式(Iterator Pattern)
- java main方法
- 一起学CC3200系列教程之ADC采集
- FFmpeg的H.264解码器源代码简单分析:概述
- 16
- 多个构造函数之间怎样相互引用??
- VFL语言
- 操作系统对堆棧内存管理的不同看出内存管理的本质
- iOS-size class