当前位置: 首页 > 后端技术 > Java

设计模式的迭代器模式

时间:2023-04-01 16:45:41 Java

本文介绍设计模式中的迭代器模式。首先对迭代器模式的基本概念和对应的四种角色进行通俗的讲解,并根据四种角色给出了典型的例子。为了加强知识Jdk源码合集的连贯性,我们进一步说明迭代器模式的应用,最后对迭代器模式的应用场景、优缺点进行说明。读者可以拉取完整代码在本地学习,上传码云实现代码测试。1.概念理解官方对迭代器模式的解释是提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。什么是聚合对象?最典型的就是集合类。也就是说,集合中的数据是私有的,集合不应该提供直接遍历的方法。必须定义一个新对象才能访问该集合。既然是专门用来遍历的对象,又是要遍历的聚合对象,那么显然至少有两个对象,迭代器对象和聚合对象。由于面向接口编程的原则,迭代器对象和聚合对象应该从接口中抽象出来,那么自然应该有四个角色:抽象聚合(InterfaceAggregate)角色:定义存储、添加、删除聚合元素的接口,并创建迭代器对象。ConcreteAggregate(ConcreteAggregate)作用:实现抽象聚合类,返回一个具体迭代器的实例。抽象迭代器(Iterator)作用:定义了访问和遍历聚合元素的接口,通常包括hasNext()、next()等方法。具体迭代器(Concretetelterator)作用:实现抽象迭代器接口中定义的方法,完成对聚合对象的遍历,并记录遍历的当前位置。下面我们根据四个角色给出一个典型案例。2、案例实现应该有四个抽象聚合角色类,用于定义元素增删改查的统一规范接口,以及创建迭代器对象的方法。具体的聚合角色实现了抽象聚合角色方法abstractiteratorrole,并定义了遍历元素的具体迭代器的统一规范接口,实现了抽象迭代器角色的方法。抽象聚合角色:/***抽象聚合角色*@authortcy*@Date13-09-2022*/publicinterfaceInterfaceAggregate{/***添加对象*@paramobjobject*/voidadd(Objectobj);/***删除对象*@paramobjobject*/voidremove(Objectobj);/***调用迭代器*@returniterator*/IteratorgetIterator();}具体聚合作用:/***具体聚合作用*@authortcy*@Date13-09-2022*/publicclassConcreteAggregateimplementsInterfaceAggregate{privateListlist=newArrayList<>();@Overridepublicvoidadd(Objectobj){list.add(obj);}@Overridepublicvoidremove(Objectobj){list.remove(obj);}@OverridepublicIteratorgetIterator(){returnnewConcretetelterator(list);}}抽象迭代器作用:/***抽象迭代器*@authortcy*@Date13-09-2022*/publicinterfaceIterator{/***deleteobject*@returnobject*/Objectremove();/***调用下一个对象*@return对象*/Enext();/***迭代迭代器中是否有下一个对象*@return*/booleanhasNext();/***遍历迭代器中剩余的对象*@paramaction*/defaultvoidforEachRemaining(Consumeraction){Objects.requireNonNull(动作);while(hasNext())action.accept(next());}}具体的迭代器角色:/***具体的迭代器角色*@authortcy*@Date13-09-2022*/publicclassConcretetelteratorimplementsIterator{privateListlist=null;私有整数索引=-1;publicConcreteterterator(Listlist){this.list=list;}@OverridepublicObjectremove(){索引=列表。尺寸();对象obj=list.get(index);list.remove(obj);返回对象;}@OverridepublicObjectnext(){Objectobj=null;if(this.hasNext()){obj=list.get(++index);}返回对象;}@OverridepublicbooleanhasNext(){if(indexSystem.out.println(ele));}}迭代器的实现逻辑比较清晰,不难理解。了解了设计模式之后,我们再趁热打铁的看看迭代器模式在源码中的应用。3.源码Jdk中集合类应用迭代器模式被广泛使用,我们以ArrayList为例。ArrayList在实现迭代器的时候,也有四种作用。列表抽象聚合类;ArrayList具体聚合作用;迭代器抽象迭代器;ArrayList内部类Itr是具体的迭代器;可以看到,ArrayList把具体的聚合作用和具体的迭代器都写在了一个类中,而Itr是具体的迭代对象,是内部类的形式。ArrayList其实和我们案例中的方法非常相似,只是在ArrayList中定义了更多的方法,而且ArrayList还有一个内部类ListItr。其实它是迭代器的增强版,在继承Itr的基础上实现了ListIterator接口。除了hasNext()、next()和remove()方法之外,Iterator迭代器还有一个特殊的forEachRemaining()方法。让我们关注forEachRemaining()方法,这意味着遍历剩余的集合。比如我们调用了集合中的第一个元素,那么遍历的时候会自动忽略第一个元素,遍历剩下的元素。下面写一个测试方法看看效果:publicclassClient{publicstaticvoidmain(String[]args){//jdkArrayListiterator//创建一个集合//向集合中添加元素collection.add("老王");collection.add("小王");collection.add("小张");//获取集合的迭代器java.util.IteratoriteratorJdk=collection.iterator();System.out.println("Arraylist聚合对象有:");//调用集合实现的迭代器的抽象方法遍历集合元素while(iteratorJdk.hasNext()){System.out.println(iteratorJdk.next());}//调用forEachRemaining()方法遍历集合元素iteratorJdk.forEachRemaining(ele->System.out.println(ele));}}Arraylist聚合对象包括:一般情况下,老王、小王、小张会将集合对象中的信息打印两次,但实际上只打印一次。正是因为next调用的元素,forEachRemaining才不会再调用。看到这里,想必你对迭代器有了初步的了解。在遍历元素时,除了使用for循环遍历元素外,它还提供了另一种遍历元素的方式。案例很容易理解,在源码中的应用也很好理解,但是实际开发中什么时候用到iterator对象呢?想必大多数人都不是很清楚。那么看看迭代器对象的应用场景、优缺点,看看能不能找到答案。4.总结当一个对象是一个聚合对象,需要对外提供遍历方法时,可以使用迭代器模式,即在实际业务中定义的聚合对象,里面存储了我们需要的业务数据,以便于使得业务数据的职责更清晰,我们可以提取编辑方法,定义一个遍历数据的迭代器对象。迭代器方法提供了遍历聚合对象的不同方式,添加新的聚合类和迭代器类更加方便。庞大的Java集合类家族正是基于这一优势采用了迭代器模式。迭代器模式具有设计模式的普遍缺点——系统的复杂性。迭代器模式将数据存储和数据遍历分开,增加了类的数量。持续更新了十几篇设计模式博客,推荐大家一起学习。1.设计模式概述2.设计模式的工厂方法和抽象工厂3.设计模式的单例和原型4.设计模式的建造者模式5.设计模式的代理模式6.设计模式的适配器模式7.设计模式的桥梁设计模式模式八、组合模式九、设计模式装饰器模式十、设计模式外观模式十一、外观模式享元模式十二、设计模式责任链模式十三、设计模式命令模式十四、设计解释器模式模式