当前位置: 首页 > 科技观察

设计模型系列——迭代器模式

时间:2023-03-18 12:40:31 科技观察

在现实生活和程序设计中,经常需要访问一个聚合对象中的每一个元素,比如《数据结构》中的链表遍历。通常的做法是把链表的创建和遍历结合起来放在同一个类中,但是这种方式不利于程序的扩展。如果要改变遍历方式,就必须修改程序源码,这就违反了“开闭原则”。既然在聚合类中封装遍历方法不可取,那么在聚合类中不提供遍历方法,用户自己实现遍历方法是否可行?答案也是不可取的,因为这种方法会有两个缺点:暴露Aggregate类的内部表示使其数据不安全;增加客户的负担。“迭代器模式”可以较好地克服上述缺点。它在客户端访问类和聚合类之间插入一个迭代器,将聚合对象与其遍历行为分开,对客户端隐藏其内部细节,满足“单一职责原则”和“开闭原则”,这样Java中的Collection、List、Set、Map等都包含迭代器。模式定义提供了一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为模式。迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成一个迭代器类来实现的。其目的是允许外部代码透明地访问聚合的内部数据,而不暴露聚合对象的内部结构。解决问题的不同方法是遍历整个集成对象。模式组成步骤第一步:定义抽象迭代器角色。迭代器的作用是负责定义访问遍历元素的接口,一般包括三个方法,分别是访问下一个元素next()、元素是否已经到达底部hasNext()、删除当前指向的元素remove().interfaceIterator{Objectfirst();Objectnext();booleanhasNext();}第二步:定义具体的迭代器角色。classConcreteIteratorimplementsIterator{privateListlist=null;privateintindex=-1;publicConcreteIterator(Listlist){this.list=list;}publicbooleanhasNext(){if(indexlist=newArrayList();publicvoidadd(Objectobj){list.add(obj);}publicvoidremove(Objectobj){list.remove(obj);}publicIteratorgetIterator(){return(newConcreteIterator(list));}}第五步:测试聚合的内容是:北京上海深圳第一:北京优势访问聚合对象的内容而不暴露其内部表示。遍历的任务由迭代器完成,简化了聚合类。它支持以不同方式遍历聚合,您甚至可以将自定义迭代器子类化以支持新的遍历。在不修改原有代码的情况下,添加新的聚合类和迭代器类非常方便。良好的封装性,为遍历不同的聚合结构提供统一的接口。缺点是增加了类的数量,一定程度上增加了系统的复杂度。应用场景当需要为聚合对象提供多种遍历方法时。当需要为遍历不同的聚合结构提供统一的接口时。在不暴露其内部细节表示的情况下访问聚合对象的内容时。由于聚合与迭代器密切相关,大多数语言在实现聚合类时都提供了迭代器类,所以大多数情况下使用语言中已有的聚合类的迭代器就足够了。模式的扩展迭代器模式通常与复合模式结合使用。在访问复合模式中的容器组件时,迭代器往往隐藏在复合模式的容器复合类中。当然,也可以构造一个外部迭代器来访问容器组件。其结构如下:源码中的应用Java中的容器对象很多,基本上都涉及到迭代器。下面以ArrayList为例,分析一下它是如何应用Iterator模式的。Java集合框架:List、Set、Map都支持ArrayList的迭代源码可查:ArrayList实现List接口,使用Object数组存储元素;List接口中定义了iterator()和很多操作集合的方法;iterator()被重写,返回一个Itr对象;Itr是ArrayList的内部类,实现了Iterator接口。部分源代码展示List接口publicinterfaceListextendsCollection{Iteratoriterator();}Iterator接口publicinterfaceIterator{booleanhasNext();Enext();defaultvoidremove(){thrownewUnsupportedOperationException("remove");}}ArrayList类和Itr类publicclassArrayListextendsAbstractListimplementsList,RandomAccess,Cloneable,java.io.Serializable{publicIteratoriterator(){returnnewItr();}//Itr内部类privateclassItrimplementsIterator{intcursor;//indexofnextelementtoreturnintlastRet=-1;//indexoflastelementreturned;-1ifnosuchintexpectedModCount=modCount;publicbooleanhasNext(){returncursor!=size;}@SuppressWarnings("unchecked")publicEnext(){checkForComodification();inti=cursor;if(i>=size)thrownewNoSuchElementException();Object[]elementData=ArrayList.this.elementData;if(i>=elementData.length)thrownewConcurrentModificationException();cursor=i+1;返回(E)elementData[lastRet=i];}publicvoidremove(){if(lastRet<0)thrownewIllegalStateException();checkForComodification();try{ArrayList.this.remove(lastRet);cursor=lastRet;lastRet=-1;expectedModCount=modCount;}catch(IndexOutOfBoundsExceptionex){thrownewConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")publicvoidforEachRemaining(Consumerconsumer){Objects.requireNonNull(consumer);finalintsize=ArrayList.this.size;inti=cursor;if(i>=size){return;}finalObject[]elementData=ArrayList.this.elementData;if(i>=elementData.length){thrownewConcurrentModificationException();}while(i!=size&&modCount==expectedModCount){consumer.accept((E)elementData[i++]);}//updateonceatendofiterationtoreduceheapwritetrafficcursor=i;lastRet=i-1;checkForComodification();}finalvoidcheckForComodification(){if(modCount!=expectedModCount)thrownewConcurrentModificationException();}}}PS:以上代码提交在Github:https://github.com/Niuh-Study/niuh-designpatterns.git