Skip to content

Commit

Permalink
1.add iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
Haoxiqiang committed Mar 13, 2015
1 parent 37ab092 commit 8222fd6
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 1 deletion.
4 changes: 3 additions & 1 deletion iterator/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# 任务表
| 作者 | 预计完成时间 |
| ------------- |:-------------:|
| [用户名](git地址) | 完成时间 |
| [haoxiqiang](https://github.com/Haoxiqiang) | 2015年3月13日 |





Expand Down
113 changes: 113 additions & 0 deletions iterator/haoxiqiang/AndroidMileage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.yuexue.tifenapp.wxapi;

import android.os.Build;

import org.apache.http.NameValuePair;

import java.util.Iterator;

/**
* Created by haoxiqiang on 15/3/13.
*/
public class AndroidMileage {

final static int[] versionCodes;
final static String[] versionMileages;
final static int size;

static {
versionCodes = new int[]{
Build.VERSION_CODES.BASE, Build.VERSION_CODES.BASE_1_1, Build.VERSION_CODES.CUPCAKE,
Build.VERSION_CODES.DONUT, Build.VERSION_CODES.ECLAIR, Build.VERSION_CODES.ECLAIR_0_1,
Build.VERSION_CODES.ECLAIR_MR1, Build.VERSION_CODES.FROYO, Build.VERSION_CODES.GINGERBREAD,
Build.VERSION_CODES.GINGERBREAD_MR1, Build.VERSION_CODES.HONEYCOMB, Build.VERSION_CODES.HONEYCOMB_MR1,
Build.VERSION_CODES.HONEYCOMB_MR2, Build.VERSION_CODES.ICE_CREAM_SANDWICH, Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1,
Build.VERSION_CODES.JELLY_BEAN, Build.VERSION_CODES.JELLY_BEAN_MR1, Build.VERSION_CODES.JELLY_BEAN_MR2,
Build.VERSION_CODES.KITKAT, Build.VERSION_CODES.KITKAT_WATCH, Build.VERSION_CODES.LOLLIPOP
};
versionMileages = new String[]{
"October 2008: The original, first, version of Android. Yay!",
"February 2009: First Android update, officially called 1.1.",
" May 2009: Android 1.5.",
"September 2009: Android 1.6.",
"November 2009: Android 2.0",
"December 2009: Android 2.0.1",
"January 2010: Android 2.1",
"June 2010: Android 2.2",
"November 2010: Android 2.3",
"February 2011: Android 2.3.3.",
"February 2011: Android 3.0.",
"May 2011: Android 3.1.",
"June 2011: Android 3.2.",
"October 2011: Android 4.0.",
"December 2011: Android 4.0.3.",
"June 2012: Android 4.1.",
"November 2012: Android 4.2, Moar jelly beans!",
"July 2013: Android 4.3, the revenge of the beans.",
"October 2013: Android 4.4, KitKat, another tasty treat.",
"Android 4.4W: KitKat for watches, snacks on the run.",
"Lollipop. A flat one with beautiful shadows. But still tasty.",
};

size = Math.min(versionCodes.length, versionMileages.length);
}

public static class Mileage implements NameValuePair {

public String name;
public String value;

@Override
public String getName() {
return name;
}

@Override
public String getValue() {
return value;
}

@Override
public String toString() {
return "versionCode:" + name + " desc:" + value;
}
}


public Iterator<Mileage> iterator() {
return new ArrayIterator();
}

private class ArrayIterator implements Iterator<Mileage> {
/**
* Number of elements remaining in this iteration
*/
private int remaining = size;

/**
* Index of element that remove() would remove, or -1 if no such elt
*/
private int removalIndex = -1;

@Override
public boolean hasNext() {
return remaining != 0;
}

@Override
public Mileage next() {
Mileage mileage = new Mileage();
removalIndex = size-remaining;
mileage.name = String.valueOf(versionCodes[removalIndex]);
mileage.value = versionMileages[removalIndex];
remaining-=1;
return mileage;
}

@Override
public void remove() {
versionCodes[removalIndex]=-1;
versionMileages[removalIndex]="It was set null";
}
}
}
Binary file added iterator/haoxiqiang/iterator_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
169 changes: 169 additions & 0 deletions iterator/haoxiqiang/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
Android设计模式源码解析之迭代器(Iterator)模式
========================================
> 本文为 [Android 设计模式源码解析](https://github.com/simple-android-framework-exchange/android_design_patterns_analysis) 中 迭代器模式 分析
> Android系统版本: 5.0
> 分析者: [haoxiqiang](https://github.com/Haoxiqiang),分析状态:完成,校对者:,校对状态:未完成


## 1. 模式介绍
### 模式的定义
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。

### 使用场景
  面向对象设计原则中的单一职责原则,对于不同的功能,我们要尽可能的把这个功能分解出单一的职责,不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
  Java JDK 1.2 版开始支持迭代器。每一个迭代器提供next()以及hasNext()方法,同时也支持remove()(1.8的时候remove已经成为default throw new UnsupportedOperationException("remove"))。对Android来说,集合Collection实现了Iterable接口,就是说,无论是List的一大家子还是Map的一大家子,我们都可以使用Iterator来遍历里面的元素,[可以使用Iterator的集合](http://docs.oracle.com/javase/8/docs/api/java/util/package-tree.html)

## 2. UML类图

 ![iterator_2.png](iterator_2.jpg)

### 角色介绍  
* hasNext:用来判断集合中是否存在未被遍历到的元素
* remove:移除元素
* next:将游标(位置)移动到下一个位置


## 3. 模式的简单实现

下面直接写出几种集合的遍历方式

### HashMap的遍历
```
HashMap<String, String> colorMap=new HashMap<>();
colorMap.put("Color1","Red");
colorMap.put("Color2","Blue");
Iterator iterator = colorMap.keySet().iterator();
while( iterator. hasNext() ){
String key = (String) iterator.next();
String value = colorMap.get(key);
}
```
### JSONObject的遍历
```
String paramString = "{menu:{\"1\":\"sql\", \"2\":\"android\", \"3\":\"mvc\"}}";
JSONObject menuJSONObj = new JSONObject(paramString);
JSONObject menuObj = menuJSONObj.getJSONObject("menu");
Iterator iter = menuObj.keys();
while(iter.hasNext()){
String key = (String)iter.next();
String value = menuObj.getString(key);
}
```
下面我们自己实现一个Iterator的集合

```
...
public Iterator<Mileage> iterator() {
return new ArrayIterator();
}
private class ArrayIterator implements Iterator<Mileage> {
/**
* Number of elements remaining in this iteration
*/
private int remaining = size;
/**
* Index of element that remove() would remove, or -1 if no such elt
*/
private int removalIndex = -1;
@Override
public boolean hasNext() {
return remaining != 0;
}
@Override
public Mileage next() {
Mileage mileage = new Mileage();
removalIndex = size-remaining;
mileage.name = String.valueOf(versionCodes[removalIndex]);
mileage.value = versionMileages[removalIndex];
remaining-=1;
return mileage;
}
@Override
public void remove() {
versionCodes[removalIndex]=-1;
versionMileages[removalIndex]="It was set null";
}
}
...
```
使用的过程如下,我们特意使用了remove方法,注意这个只是一个示例,和大多数的集合相比,该实现并不严谨

```
AndroidMileage androidMileage = new AndroidMileage();
Iterator<AndroidMileage.Mileage> iterator =androidMileage.iterator();
while (iterator.hasNext()){
AndroidMileage.Mileage mileage = iterator.next();
if(mileage.name.equalsIgnoreCase("16")){
//remove掉的是当前的这个,暂时只是置空,并未真的移掉
iterator.remove();
}
Log.e("mileage",mileage.toString());
}
```
### 原理分析
一个集合想要实现Iterator很是很简单的,需要注意的是每次需要重新生成一个Iterator来进行遍历.且遍历过程是单方向的,HashMap是通过一个类似HashIterator来实现的,我们为了解释简单,这里只是研究ArrayList(此处以Android L源码为例,其他版本略有不同)

```
@Override public Iterator<E> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator<E> {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList<E> ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}
```

* java中的写法一般都是通过iterator()来生成Iterator,保证iterator()每次生成新的实例
* remaining初始化使用整个list的size大小,removalIndex表示remove掉的位置,modCount在集合大小发生变化的时候后都会进行一次modCount++操作,避免数据不一致,前面我写的例子这方面没有写,请务必注意这点
* hasNext方法中,因为remaining是一个size->0的变化过程,这样只需要判断非0就可以得知当前遍历的是否还有未完成的元素
* next,第一次调用的时候返回array[0]的元素,这个过程中removalIndex会被设置成当前array的index
* remove的实现是直接操作的内存中的数据,是能够直接删掉元素的,不展开了

### 题外话
如果你想写一个集合的数据结构的话,通过实现Iterator来操作集合,这样能够降低学习成本,因为你让外部代码透明的访问集合内部的数据.当然在前面的例子中,你也见到了ConcurrentModificationException这个Exception,如果你在遍历的过程中,集合发生改变,变多变少,内容变化都是算,就会抛出来这个异常.

0 comments on commit 8222fd6

Please sign in to comment.