[工作中的设计模式]迭代子模式Iterator
一、模式解析
迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象
1、迭代子模式一般用于对集合框架的访问,常用的集合框架为list,set,map在实现的时候均可以支持迭代子模式
2、迭代子模式使用同意接口Iterator来完成对象的迭代,一般接口需要实现如下功能:first,next,isDone,currentItem等遍历接口
3、常用的集合框架根据访问需要,可以使用数组,链表等数据结构进行实现,使用迭代子模式可以屏蔽掉数据结构遍历时候产生的差异
4、在java中对结合的增强for循环依赖于迭代子模式实现
二、应用场景
迭代子模式在实际工作中基本无需自己进行编写,因为使用太过频繁,已经被jdk底层进行实现,所以我们使用集合框架时候直接使用就可以了,在这里,我们需要模拟ArrayList的基本实现和迭代子模式的实现。
ArrayList的基本结构为:
1、list内可以存放多个相同类型的元素,
2、元素可以重复存放
3、在jdk底层采用数组进行模拟,当存放数据容量超出数组,会对数组进行扩容,自动增加一部分容量,扩容算法为:(this.elementData.length*3)/2+1
4、继承了Iterator,可以使用迭代器进行遍历
三、场景代码
1、Iterator接口,定义迭代方法
package iterator.example;
/**
* 定义迭代器的接口
* @author zjl
* @time 2016-2-3
*
*/
public interface Iterator<E> {
public E first();
public E next();
public boolean isDone();
public int currentItem();
}
2、定义list接口,为了简化处理,此处直接继承迭代器接口
package iterator.example; public interface List<E> extends Iterator<E> {
public int size();
public boolean isEmpty();
public E remove(int index);
public int indexOf(E e);
void add(E e);
public E get(int index);
}
3、定义Arraylist,实现各方法
package iterator.example; import java.util.Arrays; public class ArrayList<E> implements List<E>{
//初始化一个数组,来保存对象
Object[] elementData;
private int size=0;
//迭代器游标
private int cursor=0;
//数组初始化
public ArrayList(int init){
elementData=new Object[init];
}
//默认构造类型,默认初始化10个元素
public ArrayList(){
this(10);
} @Override
public int size() {
return this.size;
} @Override
public boolean isEmpty() {
return this.size==0;
} @Override
public void add(E e) {
//如果list长度等于数组长度,那么将数组扩大
ensureCapacity(this.size+1);
elementData[this.size++]=e;
} @Override
public E remove(int index) {
RangeCheck(index);
//移除指定位置的元素
E e= (E) elementData[index];
for(;index<this.size;index++){
elementData[index]=elementData[index+1];
}
elementData[index--]=null;
return e;
} @Override
public int indexOf(E e) {
// TODO Auto-generated method stub
return 0;
}
//判断是否超长,如果超长,则扩展数组
public void ensureCapacity(int minCapacity){
int oldCapacity=this.elementData.length;
if(minCapacity>oldCapacity){
int newLength=(this.elementData.length*3)/2+1;
Object[] oldDate=this.elementData;
this.elementData=Arrays.copyOf(elementData, newLength);
} }
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
}
@Override
public E first() {
return (E) elementData[0];
}
@Override
public E next() {
if(isDone()){
throw new IndexOutOfBoundsException("the list is done");
}
return (E) elementData[cursor++];
}
@Override
public boolean isDone() {
return cursor==size;
}
@Override
public int currentItem() {
// TODO Auto-generated method stub
return cursor;
}
@Override
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
}
4、编写客户端程序
package iterator.example; public class Client { /**
* @param args
*/
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("java");
list.add("c++");
list.add("python");
list.add("Object-c");
while(!list.isDone()){
System.out.println(list.next());
}
} }
5、执行结果
java
c++
python
Object-c
四、解决差异问题
此时,虽然可以正常使用迭代器进行循环,但是很明显和jdk中的ArrayList迭代方式不一致,而且无法使用增强循环模式for..in,观察下jdk的实现,我们发现list并没有实现Iterator接口,而是使用了Iterable接口作为过渡,在Iterable中保存了Iterator的引用。
修改代码为List继承jdk的Iterable,注意,此处必须引用jdk的接口才能增强循环,修改ArrayList代码为,增加方法为:
@Override
public Iterator<E> iterator() { return new Iterator<E>() {
private int cursor=0;
@Override
public boolean hasNext(){
return cursor!=size;
} @Override
public E next() {
return (E) elementData[cursor++];
}
//仅仅为了遍历,此方法暂不实现
@Override
public void remove() { } };
}
此时客户端可以使用与原生一样的迭代方法
Iterator<String> it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
} for(String s:list){
System.out.println(s);
}
为什么不直接继承Iterator接口,反而使用过渡呢,原因大概如下:
针对集合进行迭代时候,需要使用游标标记当前迭代位置,如果多个位置同时对一个集合进行迭代的话,那么同时需要多个游标来标记当前已经迭代的位置,如果直接继承Iterator接口,那么游标必须保持在集合框架本身,必然造成迭代的冲突,所以使用Iterable,每次开始迭代时候,返回一个Iterator的实现方法,产生一个游标,这样多次迭代不会产生相互冲突。
[工作中的设计模式]迭代子模式Iterator的更多相关文章
- [设计模式]迭代子模式 Iterator
迭代子模式又叫做游标cursor模式,是对象的行为模式.迭代子模式可以顺序的访问一个聚集中的元素而不必暴露聚集的内部表象. 迭代子模式被广泛的应用在Java语言的API中的几个设计模式之一.在Java ...
- [工作中的设计模式]备忘录模式memento
一.模式解析 备忘录对象是一个用来存储另外一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把 ...
- java设计模式----迭代子模式
顺序访问聚集中的对象,主要用于集合中.一是需要遍历的对象,即聚集对象,二是迭代器对象,用于对聚集对象进行遍历访问. 迭代子模式为遍历集合提供了统一的接口方法.从而使得客户端不需要知道聚集的内部结构就能 ...
- [工作中的设计模式]享元模式模式FlyWeight
一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持 ...
- [工作中的设计模式]原型模式prototype
一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.pro ...
- 设计模式 - 迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释
迭代模式(iterator pattern) Java 迭代器(Iterator) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考迭代器模式(ite ...
- [工作中的设计模式]解释器模式模式Interpreter
一.模式解析 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 以上是解释器模式的类图,事实上我 ...
- [工作中的设计模式]中介模式模式Mediator
一.模式解析 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互. 中介模式又叫调停者模式,他有如下特点: 1.有多个系统或者对 ...
- [工作中的设计模式]责任链模式chain
一.模式解析 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知 ...
随机推荐
- BZOJ3172: [Tjoi2013]单词
传送门 做了这么多题怎么还是无法很好的理解AC自动机呢..果然是个制杖 首先题意表述不是很清晰,这些所有的单词组成了那个文章,所以果断建个AC自动机,建的时候给每个点附加一个权值,建树是经过一次权值即 ...
- dos 固定ip命令
dos 固定ip命令 ***************************************************************************************** ...
- web service 学习
是什么? 是一种远程调用技术,这种技术提供一些接口,这些接口实现让客户端和服务端进行通信和数据交换,并且让通信和交换与平台和开发语言无关.也可以说是提供了许多函数.客户端调用服务端的函数. 远程调用: ...
- [Nhibernate]SchemaExport工具的使用(二)——创建表及其约束、存储过程、视图
目录 写在前面 文档与系列文章 表及其约束 存储过程 视图 总结 写在前面 由于一直在山西出差,有几天没更新博客了.昨晚回到家,将博客园最近三天更新的文章搜集了一下,花费了半天的时间,看了看,有些文章 ...
- js闭包的作用域以及闭包案列的介绍:
转载▼ 标签: it js闭包的作用域以及闭包案列的介绍: 首先我们根据前面的介绍来分析js闭包有什么作用,他会给我们编程带来什么好处? 闭包是为了更方便我们在处理js函数的时候会遇到以下的几 ...
- PHP格式化显示文件大小函数
用filesize() 函数可以返回文件的大小,可是返回值是以字节(B)为单位的,看起来不方便.怎么让它根据文件的大小自动以KB.MB.GB为单位显示呢,用下面这个函数就可以实现了. <?php ...
- js的继承
js要实现继承有很多方法,个人总结大致分为三种: function people(){ this.specials = "人类"; } function p1(name){ thi ...
- Node.js入门学习笔记(一)
先来个最常见的"Hello World!". 打开你最喜欢的编辑器(我用的是Sublime Text),创建一个helloWorld.js的文件.我们要做的就是向stdout输出& ...
- js跨域解决方案(转载)
1.什么是跨域 我们经常会在页面上使用ajax请求访问其他服务器的数据,此时,客户端会出现跨域问题. 跨域问题是由于javascript语言安全限制中的同源策略造成的. 简单来说,同源策略是指一段脚本 ...
- php,nginx重启
查看php运行目录命令:which php/usr/bin/php 查看php-fpm进程数:ps aux | grep -c php-fpm 查看运行内存/usr/bin/php -i|grep ...