迭代器模式(控制訪問集合中的元素)

正文

JDK中已經(jīng)為我們提供了大量實現(xiàn)了迭代器的容器類磺平。
因此我們可以不用關(guān)心遏佣,諸如:LinkedlistArrayList之間的差別捉貌,卻仍能保障我們完成工作昔穴。

現(xiàn)在我們需要思索霹菊,JDK是怎么做到這一切的剧蚣?現(xiàn)在讓我們先利用迭代器實現(xiàn)一個數(shù)組類型Array,這個類型需要支持添加旋廷、移除鸠按、遍歷操作。

實現(xiàn)

STEP 1

定義迭代器接口饶碘,實現(xiàn)該接口的類擁有迭代器職責目尖。這叫好像在20年前,家門口停了一輛小汽車扎运,別人都會知道你是萬元戶一樣瑟曲。

public interface Iterable<T> {
    Iterator<T> iterator();
}

STEP 2

定義迭代器對象,除卻基本的hasNext豪治、next方法洞拨。額外定義了addremove方法负拟,這會輔助我們操作集合中的元素烦衣。

注意:迭代器不僅僅為了{迭代},而是為了{操作}集合中的元素齿椅。

public interface Iterator<E> {
    boolean hasNext();

    E next();

    boolean add(E e);

    boolean addAll(Collection<? extends E> e);

    boolean remove(E e);
}

STEP 3

實現(xiàn)一個數(shù)組Array模擬數(shù)組的操作琉挖,所有訪問集合中元素的操作全權(quán)委托給iterator對象。Array并不關(guān)心操作元素的細節(jié)涣脚,它只向外暴露操作接口示辈,對收到的請求轉(zhuǎn)發(fā)給iterator處理。

public class Array<E> implements Iterable<E> {

    private transient Iterator<E> iterator;

    public Array() {
        this.iterator = iterator();
    }

    public Array(Collection<? extends E> collection) {
        this.iterator = iterator();
        this.iterator.addAll(collection);
    }

    @Override
    public Iterator<E> iterator() {
        synchronized (this) {
            if (iterator == null) {
                iterator = new ArrayIteratorImpl<>();
            }
        }
        return iterator;
    }

    public void add(E e) {
        this.iterator.add(e);
    }

    public void addAll(Collection<? extends E> e) {
        this.iterator.addAll(e);
    }

    public void remove(E e) {
        this.iterator.remove(e);
    }

}

STEP 4

定義迭代器實現(xiàn)類遣蚀,使用接口抽象迭代器是為了滿足開閉原則矾麻,這樣Array可以隨時更換迭代器而不會影響現(xiàn)有的接口。

ArrayIteratorImpl迭代器實現(xiàn)了對數(shù)組的添加芭梯、移除操作险耀,如何分配元素、選擇用什么容器存儲玖喘、遍歷的順序甩牺、甚至是否啟用并行操作,這些對于Array都是不可感知的累奈。


public class ArrayIteratorImpl<E> implements Iterator<E> {

    private transient Object[] elementData = {};
    private transient static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    private static final int DEFAULT_CAPACITY = 10;
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    protected transient int modCount = 0;
    private int size;

    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    @Override
    public boolean hasNext() {
        return cursor != size;
    }

    @Override
    public E next() {
        int i = cursor;
        if (i >= size)
            throw new IllegalArgumentException("");
        Object[] elementData = this.elementData;
        if (i >= elementData.length)
            throw new IllegalArgumentException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    @Override
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        lastRet = -1;
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> e) {
        final Object[] a = e.toArray();
        final int numNew = e.size();
        ensureCapacityInternal(this.size + numNew);
        System.arraycopy(a, 0, elementData, size, numNew);
        this.size += numNew;
        lastRet = -1;
        return numNew != 0;
    }

    @Override
    public boolean remove(E o) {
        lastRet = -1;
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

}

STEP 5

客戶端調(diào)用測試

public class Client {

    public static void main(String[] args) {
        Array<String> array = new Array();
        array.add("清華大學(xué)");
        array.add("北京大學(xué)");
        array.add("浙江大學(xué)");
        array.add("武漢大學(xué)");
        array.add("西安交通大學(xué)");
        array.add("上海交通大學(xué)");
        array.add("人民大學(xué)");


        Iterator<String> iterator = array.iterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(item);
        }
    }
}

總結(jié)

迭代器模式屬于行為模式類別贬派。

迭代器本質(zhì):控制訪問集合中的元素

迭代器模式.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末急但,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子搞乏,更是在濱河造成了極大的恐慌波桩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件请敦,死亡現(xiàn)場離奇詭異镐躲,居然都是意外死亡,警方通過查閱死者的電腦和手機侍筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門萤皂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匣椰,你說我怎么就攤上這事敌蚜。” “怎么了窝爪?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵弛车,是天一觀的道長。 經(jīng)常有香客問我蒲每,道長纷跛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任邀杏,我火速辦了婚禮贫奠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘望蜡。我一直安慰自己唤崭,他們只是感情好,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布脖律。 她就那樣靜靜地躺著谢肾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪小泉。 梳的紋絲不亂的頭發(fā)上芦疏,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機與錄音微姊,去河邊找鬼酸茴。 笑死,一個胖子當著我的面吹牛兢交,可吹牛的內(nèi)容都是我干的薪捍。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酪穿!你這毒婦竟也來了与倡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤昆稿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后息拜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溉潭,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年少欺,在試婚紗的時候發(fā)現(xiàn)自己被綠了喳瓣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡赞别,死狀恐怖畏陕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仿滔,我是刑警寧澤惠毁,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站崎页,受9級特大地震影響鞠绰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜飒焦,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一蜈膨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧牺荠,春花似錦翁巍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杈曲,卻和暖如春例朱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鱼蝉。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工洒嗤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人魁亦。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓渔隶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子间唉,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容