当前位置 博文首页 > JavaEdge全是干货的技术号:阿里华为等大厂如何实践迭代器模式的
基本不会有人业务开发使用的模式,没人会单独写一个迭代器,除非是产品性质的开发。
迭代器是为容器服务的,例如Collection、Map等,迭代器模式就是为解决遍历这些容器中的元素而生。
容器只要负责新增、移除元素即可,遍历由迭代器进行。
我们来看迭代器模式的通用源代码
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
具体迭代器
public class ConcreteIterator implements Iterator {
private Vector vector = new Vector();
//定义当前游标
public int cursor = 0;
@SuppressWarnings("unchecked")
public ConcreteIterator(Vector _vector){
this.vector = _vector;
}
//判断是否到达尾部
public boolean hasNext() {
if(this.cursor == this.vector.size()){
return false;
}else{
return true;
}
}
//返回下一个元素
public Object next() {
Object result = null;
if(this.hasNext()){
result = this.vector.get(this.cursor++);
}else{
result = null;
}
return result;
}
//删除当前元素
public boolean remove() {
this.vector.remove(this.cursor);
return true;
}
}
开发系统时,迭代器的删除方法应该完成两个逻辑:
删除当前元素
当前游标指向下一个元素
抽象容器
public interface Aggregate {
//是容器必然有元素的增加
public void add(Object object);
//减少元素
public void remove(Object object);
//由迭代器来遍历所有的元素
public Iterator iterator();
}
public class ConcreteAggregate implements Aggregate {
//容纳对象的容器
private Vector vector = new Vector();
//增加一个元素
public void add(Object object) {
this.vector.add(object);
}
//返回迭代器对象
public Iterator iterator() {
return new ConcreteIterator(this.vector);
}
//删除一个元素
public void remove(Object object) {
this.remove(object);
}
}
public class Client {
public static void main(String[] args) {
//声明出容器
Aggregate agg = new ConcreteAggregate();
//产生对象数据放进去
agg.add("abc");
agg.add("aaa");
agg.add("1234");
//遍历一下
Iterator iterator = agg.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
简单地说,迭代器就类似于一个数据库中的游标,可以在一个容器内上下翻滚,遍历所有它需要查看的元素。
我们在例子中使用了迭代器模式后为什么使原本简单的应用变得复杂起来了呢?那是因为我们在简单的应用中使用了迭代器,在哪?
注意这段话
for(IProject project:projectList)
它为什么能够运行起来?还不是因为ArrayList已经实现了iterator()方法,我们才能如此简单地应用。
从JDK 1.2版本开始增加java.util.Iterator这个接口,并逐步把Iterator应用到各个聚集类(Collection)中,我们来看JDK 1.5的API帮助文件,你会看到有一个叫java.util.Iterable的接口
看看有多少个接口继承了它:
BeanContext,BeanContextServices,BlockingQueue,Collection,List,Queue,Set,SortedSet
再看看有它多少个实现类:AbstractCollection,AbstractList,AbstractQueue,AbstractSequentialList,AbstractSet,ArrayBlockingQueue,ArrayList,AttributeList,BeanContextServicesSupport,BeanContextSupport,ConcurrentLinkedQueue,CopyOnWriteArrayList,CopyOnWriteArraySet,DelayQueue,EnumSet,HashSet,JobStateReasons,LinkedBlockingQueue,LinkedHashSet,LinkedList,PriorityBlockingQueue,PriorityQueue,RoleList,RoleUnresolvedList,Stack,SynchronousQueue,TreeSet,Vector
基本上我们经常使用的类都在这个表中了,也正是因为Java把迭代器模式已经融入到基本API中了,我们才能如此轻松、便捷。
我们再来看看Iterable接口。java.util.Iterable接口只有一个方法:iterator(),也就说,通过iterator()这个方法去遍历聚集类中的所有方法或属性,基本上现在所有的高级语言都有Iterator这个接口或者实现,Java已经把迭代器给我们准备好了,我们再去写迭代器,就有点多余了。所以呀,这个迭代器模式也有点没落了,基本上很少有项目再独立写迭代器了,直接使用Collection下的实现类就可以完美地解决问题。
迭代器现在应用得越来越广泛了,甚至已经成为一个最基础的工具。一些大师级人物甚至建议把迭代器模式从23个模式中删除,为什么呢?就是因为现在它太普通了,已经融入到各个语言和工具中了,比如PHP中你能找到它的身影,Perl也有它的存在,甚至是前台的页面技术AJAX也可以有它的出现(如在Struts2中就可以直接使用iterator)。基本上,只要你不是在使用那些古董级(指版本号)的编程语言的话,都不用自己动手写迭代器。
分离了集合对象的遍历行为
类的个数成对增加
现在还在开发或者维护的几百个项目,信息很乱,能否先把这些项目最新情况重新打印一份给我?
public interface IProject {
// 从老板这里看到的就是项目信息
public String getProjectInfo();
}
public class Project implements IProject {
//项目名称
private String name = "";
//项目成员数量
private int num = 0;
//项目费用
private int cost = 0;
//定义一个构造函数,把所有老板需要看到的信息存储起来
public Project(String name,int num,int cost){
//赋值到类的成员变量中
this.name = name;
this.num = num;
this.cost=cost;
}
//得到项目的信息
public String getProjectInfo() {
String info = "";
//获得项目的名称
info = info+ "项目名称是:" + [this.name](http://this.name/);
//获得项目人数
info = info + "\t项目人数: "+ this.num;
//项目费用
info = info+ "\t 项目费用:"+ this.cost;
return info;
}
}
通过构造函数把要显示的数据传递过来,然后放到getProjectInfo中显示
public class Boss {
public static void main(String[] args) {
//定义一个List,存放所有的项目对象
ArrayList projectList = new ArrayList();
//增加星球大战项目
projectList.add(new Project("星球大战项目",10,100000));
//增加扭转时空项目
projectList.add(new Project("扭转时空项目",100,10000000));
//增加超人改造项目
projectList.add(new Project("超人改造项目",10000,1000000000));
//这边100个项目
for(int i=4;i<104;i++){
projectList.add(new Project("第"+i+"个项目",i*5,i*1000000));
}
//遍历一下ArrayList,把所有的数据都取出
for(IProject project:projectList){
System.out.println(project.getProjectInfo());
}
}
}
然后看一下我们的运行结果,如下所示: