メインコンテンツへ移動

デザインパターン之イテレーターパターン(Iterator Pattern)

無料2015-03-07#Design_Pattern#迭代器模式#Iterator Pattern

イテレーターパターンは比較的シンプルなパターンで、端的に言えばイテレーターを使って走査の詳細をカプセル化します。コレクションオブジェクトのほとんどは走査操作をサポートします(Array、List、Set、Map など)が、各コレクションオブジェクトの内部実装方法が異なるため、走査時に呼び出す必要があるインターフェースも異なります。イテレーターはコレクションオブジェクトに統一されたインターフェースを提供して走査操作をサポートするためのものです

no_mkd

一。イテレーターパターンとは何か?

イテレーターを使ってコレクションオブジェクトの走査詳細をカプセル化し、呼び出し者が統一されたインターフェースを通じてコレクションの走査を実現できるようにします

イテレーターはコレクションオブジェクトにある程度の保護も提供します。コレクションを走査したい場合、イテレーターのメソッドを直接呼び出すだけでよく、コレクション内部のデータ管理方式を知る必要もありませんし、知る必要もありません

二。例を挙げる

現在一組のカスタムオブジェクトがあると仮定します。それらがどのようなコレクションオブジェクトで維持されているかはわかりません。Array、List または其它かもしれません。私たちの仕事はこの一組のオブジェクトを走査することです(または走査の基础上でいくつかの追加処理を追加します)。どのように実装するかを考えてみましょう?

まずコレクションオブジェクトのタイプを判断し、それぞれ異なる処理を行います。すべての異なるコレクションタイプに対して、異なるループ来处理する必要があります。これらのループブロックにはわずかな違いしかありませんが、ループを提供して処理する必要があります。。100 種類の異なるコレクションタイプがある場合、おそらく 100 個の彼此差不多的なループを使って走査を実装する必要があるでしょう。无疑に大量の冗長コードが存在します。したがって、統一された入口が必要で、n 個のループを非常に適応性の高い 1 つのループに変えたいと思います。ではイテレーターがまさに私たちが朝思暮想していた統一���れた入口です:

イテレーターインターフェース

package IteratorPattern;

/**

  • @author ayqy

  • イテレーターの定義 */ public interface Iterator {

    /**

    • @return コレクション内に次の要素が存在するかどうか / public abstract boolean hasNext(); /*
    • @return コレクション内の次の要素を返す */ public abstract Object next(); }

いくつかの具体的なイテレーターを実装して走査詳細を実装する必要があります:

Array イテレーター:

package IteratorPattern;

/**

  • @author ayqy

  • 配列イテレーターの実装 */ public class ArrayIterator implements Iterator{ MyObject[] arr;//カスタムオブジェクト配列 int index = 0;//現在のインデックス

    public ArrayIterator(MyObject[] arr){ this.arr = arr; }

    @Override public boolean hasNext() { if(index < arr.length && arr[index] != null) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = arr[index]; index++;

     return mo;
    

    } }

P.S.Array イテレーターの hasNext メソッドの具体実装に注意してください

List イテレーター:

package IteratorPattern;

import java.util.List;

/**

  • @author ayqy

  • List イテレーターの実装 */ public class ListIterator implements Iterator{ List<MyObject> list;//コレクションオブジェクト int index = 0;//現在のインデックス

    public ListIterator(List<MyObject> list){ this.list = list; }

    @Override public boolean hasNext() { if(index < list.size()) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = list.get(index); index++;

     return mo;
    

    } }

これらの具体的なイテレーターがあれば、1 つのループだけで済みます:

/**
 * コレクションのすべての内容を印刷
 * @param iter コレクションのイテレーター
 */
private static void printObjs(Iterator iter){
	while(iter.hasNext()){
		System.out.println(iter.next().toString());
	}
}

三。Java の Iterator サポート

イテレーターの便利さと必要性により、Java1.5 以降は Iterator のサポートを提供しています。現在多くのコレクションオブジェクトが Iterator をサポートしています。例えば Set, List, Map, SortedSet, SortedMap, HashSet, TreeSet, ArrayList, LinkedList, Vector などです

イテレーターをサポートしていない唯一のものは配列かもしれません(スタック、キューこれらの特殊なものを除く)。上記でカスタムの Iterator インターフェースを実装しましたが、実際 Java 自体がこのインターフェースを提供しています(java.util.Iterator)。ただし異なる点は:

Java.util.Iterator インターフェースは 3 つのメソッドを定義しています(hasNext、next メソッドの他に remove メソッドもあります):

コレクションオブジェクトが remove メソッドを提供したくない場合でも関係ありません。例外をスローして実装を拒否できます。このように:

package IteratorPattern;

/**

  • @author ayqy

  • Java が提供する Iterator インターフェースを使用して配列イテレーターを実装 */ public class JavaArrayIterator implements java.util.Iterator{ MyObject[] arr;//カスタムオブジェクト配列 int index = 0;//現在のインデックス

    public JavaArrayIterator(MyObject[] arr){ this.arr = arr; }

    @Override public boolean hasNext() { if(index < arr.length && arr[index] != null) return true;

     return false;
    

    }

    @Override public Object next() { MyObject mo = arr[index]; index++;

     return mo;
    

    }

    @Override public void remove() { //操作サポートされていない例外をスロー throw new UnsupportedOperationException(); } }

イテレーターの呼び出し方式は完全に変わっていません:

/**
 * コレクションのすべての内容を印刷
 * @param iter コレクションのイテレーター
 */
private static void printObjs(java.util.Iterator iter){
	while(iter.hasNext()){
		System.out.println(iter.next().toString());
	}
}

四。イテレーターの暗黙的呼び出し

多くの言語が for each(または for in)ループをサポートしており、その内部実装はイテレーターを呼び出して走査を完了します。もちろん、これは小さな常識に過ぎません。より重要なのはイテレーターの設計原理を学び、必要な時に独自のイテレーターを定義することです

五。拡張

イテレーターパターン自体は比較的シンプルで、もはや独自のイテレーターを定義する必要さえありません(API が提供するイテレーターインターフェースはほぼ私たちのニーズを満たせます)

ただしイテレーターとコンポジットパターンを組み合わせると、いくつかの信じられないようなことができます(コンポジットパターンで詳しく紹介します。ここをクリックしてジャンプ>>

コメント

コメントはまだありません

コメントを書く