デザインパターン_動作パターン_《イテレータパターン》
ダークホースプログラマによるJavaデザインパターンの詳細解説、23のJavaデザインパターン(図表+フレームワークソースコード解析+実戦)をノートとしてまとめています。
概要
意味
- 集約オブジェクトの内部表現を公開せずに、集約オブジェクト内のデータ範囲に順次アクセスするためのオブジェクトを提供します。
構造
Iterator Pattern には主に次の役割が含まれます。
-
抽象集約 (集約) ロール: 集約された要素の保存、追加、削除、および反復子オブジェクトの作成のためのインターフェイスを定義します。
-
具体的な集合体の役割: 抽象的な集合体クラスを実装し、具体的なイテレータのインスタンスを返します。
-
抽象反復子 (Iterator) の役割: 通常、hasNext()、next()、およびその他のメソッドを含む、集約要素にアクセスして走査するためのインターフェイスを定義します。
-
具象反復子 (具象反復子) の役割: 抽象反復子インターフェースで定義されたメソッドを実装し、集約されたオブジェクトの走査を完了し、走査の現在位置を記録します。
事例の実現
[例] Student オブジェクトを格納できるコンテナ オブジェクトを定義し、そのコンテナをトラバースする機能をイテレータに渡す 対象となるクラスは以下のとおりです。
コードは以下のように表示されます:
-
抽象イテレータの役割 - イテレータ インターフェイス、hasNext()、next() メソッドを宣言
public interface StudentIterator { // 判断是否还有元素 boolean hasNext(); // 获取下一个元素 Student next(); }
-
すべての抽象メソッドをオーバーライドする具象イテレータ ロール クラス
public class StudentIteratorImpl implements StudentIterator { private List<Student> list; private int position = 0; // 记录遍历时的位置 public StudentIteratorImpl(List<Student> list) { this.list = list; } // 判断是否还有元素 @Override public boolean hasNext() { return position < list.size(); } // 获取下一个元素 @Override public Student next() { // 从集合中获取指定位置的元素 Student currentStudent = list.get(position); position++; return currentStudent; } }
-
抽象コンテナ クラス (抽象集約ロール)。要素の追加、要素の削除、イテレータ オブジェクトの取得のためのメソッドが含まれます。
public interface StudentAggregate { // 添加学生功能 void addStudent(Student student); // 删除学生功能 void removeStudent(Student student); // 获取迭代器对象功能 StudentIterator getStudentIterator(); }
-
具象コンテナ クラス (具象集約ロール)、すべてのメソッドをオーバーライドします。
public class StudentAggregateImpl implements StudentAggregate { private List<Student> list = new ArrayList<Student>(); // 学生列表 // 添加学生功能 @Override public void addStudent(Student student) { this.list.add(student); } // 删除学生功能 @Override public void removeStudent(Student student) { this.list.remove(student); } // 获取迭代器对象功能 @Override public StudentIterator getStudentIterator() { // 创建迭代器对象 return new StudentIteratorImpl(list); } }
-
学生クラス
public class Student { private String name; private String number; // getter/setter... public Student(String name, String number) { this.name = name; this.number = number; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", number='" + number + '\'' + '}'; } }
-
テストクラス
public class Client { public static void main(String[] args) { // 创建聚合对象 StudentAggregateImpl aggregate = new StudentAggregateImpl(); // 添加元素 aggregate.addStudent(new Student("张三", "001")); aggregate.addStudent(new Student("李四", "002")); aggregate.addStudent(new Student("王五", "003")); aggregate.addStudent(new Student("赵六", "004")); /* * 遍历聚合对象 */ // 1.获取迭代器对象 StudentIterator iterator = aggregate.getStudentIterator(); // 2.遍历 while (iterator.hasNext()) { // 3.获取元素 Student student = iterator.next(); System.out.println(student.toString()); } } }
出力
Student{name='张三', number='001'} Student{name='李四', number='002'} Student{name='王五', number='003'} Student{name='赵六', number='004'}
長所と短所
アドバンテージ
- さまざまな方法で集約オブジェクトを走査することがサポートされており、同じ集約オブジェクトに対して複数の走査メソッドを定義できます。イテレータ モードでは、元のイテレータを別のイテレータに置き換えてトラバーサル アルゴリズムを変更するだけでよく、新しいトラバーサル メソッドをサポートするためにイテレータのサブクラスを定義することもできます。
- イテレータは集計クラスを簡素化します。イテレータの導入により、元の集計オブジェクトでデータ トラバーサルなどのメソッドを提供する必要がなくなり、集計クラスの設計を簡素化できます。
- イテレータ モードでは、抽象化レイヤの導入により、元のコードを変更せずに新しい集計クラスとイテレータ クラスを追加することが非常に便利であり、「開始と終了の原則」の要件を満たします。
欠点がある
- クラスの数が増加したため、システムの複雑さがある程度増加しました。
使用するシーン
- 集約オブジェクトに対して複数の走査メソッドを提供する必要がある場合。
- 異なる集約構造を横断するための統一インターフェイスを提供する必要がある場合。
- 内部詳細の表現を公開せずに集約オブジェクトのコンテンツにアクセスする場合。
JDKソースコード解析 - コレクションクラス
イテレータ モードは Java の多くのコレクション クラスで広く使用されています。Java ソース コードでイテレータ モードがどのように使用されるかを見てみましょう。
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); // list.iterator()方法返回的肯定是Iterator接口的子实现类对象
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
このコードを読んだ後、見覚えはありますか? 基本的には上記のコードと似ています。すべての単一列コレクションではイテレータが使用されます。例として ArrayList を見てみましょう。
- リスト: 抽象集約クラス
- ArrayList: 具象集計クラス
- イテレータ: 抽象イテレータ
- list.iterator():
Iterator
インターフェイスを実装する特定のイテレータ オブジェクトを返します (ArrayList では、内部クラス Itr です)。
特に ArrayList のコード実装を見てください。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public Iterator<E> iterator() {
// 返回的肯定是Iterator的子实现类对象
return new Itr();
}
||
\/
// 内部类Itr 实现了Iterator接口 并且重写了 hasNext() 和 next() 方法。
private class Itr implements Iterator<E> {
int cursor; // 下一个要返回元素的索引
int lastRet = -1; // 上一个返回元素的索引
int expectedModCount = modCount;
Itr() {
}
// 判断是否还有元素
public boolean hasNext() {
return cursor != size;
}
// 获取下一个元素
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
...
}
コードのこの部分は比較的単純です。大まかに言うと、iterator
インスタンス化されたIterator
オブジェクトがメソッドで返されます。Itr は内部クラスであり、Iterator
インターフェイスを実装し、その中の抽象メソッドを書き換えます。
知らせ:
Java で開発している場合、イテレータ モードを使用したい場合は、独自定義のコンテナ クラスを実装し、
java.util.Iterable
その中に iterator() メソッドを実装して、 のjava.util.Iterator
実装クラスを返すだけで済みます。