説明:記事のデザインパターンシリーズは読むことです刘伟
書かれた《设计模式的艺术之道(软件开发人员内功修炼之道)》
ノートを読むために本を。個人的にはこの本はとてもいいと思いますし、読んでみたいです。詳細については、この本の著者のブログを確認することもできhttps://blog.csdn.net/LoveLion/article/details/17517213
ます。
モードの概要
パターン定義
ソフトウェア開発では、一連のデータを格納するために集約オブジェクトを使用する必要があることがよくあります。集合オブジェクトには2つの役割があります。
- データを保存する
- トラバースデータ
依存関係の観点からすると、前者は集合オブジェクトの基本的な責任であり、後者は可変であり、分離可能です。したがって、データの振る舞いを介してパッケージ化と呼ばれる、集合オブジェクトから分離することができる迭代器
ことにより、被写体迭代器
単一責任とより一致する、集約オブジェクトの設計を簡素化するであろう、重合を横断するオブジェクト内のデータを提供する行為要件。
イテレーターパターン(
Iterator Pattern
):オブジェクトの内部ストレージを公開せずに集約オブジェクトにアクセスする方法を提供します。イテレータパターンは、オブジェクトの動作パターンです。
パターン構造図
イテレータのパターン構造には、アグリゲーションとイテレータの2つの階層構造があり、システムの柔軟性とスケーラビリティを考慮して、パターンはイテレータ工厂方法
パターンに適用され、そのパターン構造を図に示します。
反復子パターン構造図には、次の役割が含まれています。
Iterator
(抽象迭代器
):要素にアクセスしてトラバースするためのインターフェースを定義し、データ要素をトラバースするためのメソッドを宣言します。例:最初の要素を取得するfirst()
ためのメソッド、次の要素にアクセスするためのnext()
メソッド、まだ存在するかどうかを判断するためのメソッド次の要素のhasNext()
メソッド、現在の要素を取得するcurrentItem()
メソッドなど、これらのメソッドは特定のイテレータで実装されます。ConcreteIterator
(具体迭代器
):抽象イテレータインターフェースを実装し、集約オブジェクトの走査を完了し、同時に特定のイテレータのカーソルを介して集約オブジェクトの現在の位置を記録します。特定の実装では、カーソルは通常、位置です負でない整数。Aggregate
(抽象聚合类
):要素オブジェクトを格納および管理createIterator()
し、イテレーターオブジェクトを作成するメソッドを宣言し、抽象イテレーターファクトリロールとして機能するために使用されます。ConcreteAggregate
(具体聚合类
):抽象集約クラスcreateIterator()
で宣言されたメソッドを実装し、具象集約クラスに対応する具象イテレータConcreteIterator
インスタンスを返します。
パターン疑似コード
抽象迭代器
重合方法は、オブジェクト格納された要素を横断するために宣言され
interface Iterator {
public void first(); //将游标指向第一个元素
public void next(); //将游标指向下一个元素
public boolean hasNext(); //判断是否存在下一个元素
public Object currentItem(); //获取游标指向的当前元素
}
で具体迭代器
ealization 抽象迭代器
データを横断する宣言されたメソッド
class ConcreteIterator implements Iterator {
private ConcreteAggregate objects; //维持一个对具体聚合对象的引用,以便于访问存储在聚合对象中的数据
private int cursor; //定义一个游标,用于记录当前访问位置
public ConcreteIterator(ConcreteAggregate objects) {
this.objects=objects;
}
public void first() { ...... }
public void next() { ...... }
public boolean hasNext() { ...... }
public Object currentItem() { ...... }
}
聚合类
データを格納する负责创建迭代器对象
ための最も簡単な抽象聚合类
コードは次のとおりです
interface Aggregate {
Iterator createIterator();
}
具象集約クラスは、抽象集約クラスのサブクラスです。一方で、データの格納を担当します。一方、抽象集約クラスで宣言されたファクトリメソッドは、具象集約クラスにcreateIterator()
対応する特定のイテレータオブジェクトを返すように実装されています。コードは次のとおりです。示されている
class ConcreteAggregate implements Aggregate {
//......
public Iterator createIterator() {
return new ConcreteIterator(this);
}
//......
}
モードの改善
図反復モードの構造では、我々は、コンクリートを見ることができ迭代器类
、コンクリートは聚合类
関係があり、二重関係の間に存在し关联关系
、特に、迭代器
特定の集約オブジェクトへの参照を維持する必要性、関連オブジェクトである访问存储在聚合对象中的数据
イテレータすることができるようにしますこれらのデータを走査します。
を使用するだけでなく关联关系
、イテレータが集約オブジェクトのデータにアクセスできるようにするために、イテレータクラスを集約クラスとして設計することもでき内部类
ます。JDKのイテレータクラスは、次のAbstractList
コードスニペットに示すように、このメソッドによって実装されます。示されている
package java.util;
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//...
public boolean add(E e) {...}
abstract public E get(int index);
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
//...
public Iterator<E> iterator() {
return new Itr();
}
// 这里用内部类可直接访问到聚合对象中的数据
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
//...
}
public void remove() {
//...
}
}
}
パターン適用
JDKでのパターンの適用
JDKでは、Collection
インターフェイスとIterator
インターフェイスは、抽象層反復モードとして働きに対応する抽象聚合类
と抽象迭代器
しながら、Collection
サブクラスインターフェースは、として機能具体聚合类
ショーの下に、その関連するクラスとリストJDK部との関係を示します。
JDKでは、実際の状況は上記の図よりもはるかに複雑です。インターフェースは、List
インターフェースを継承Collection
するiterator()
メソッドに加えて、listIterator()
特にListIterator
タイプイテレータの作成に使用される新しいファクトリメソッドを追加します。このメソッドはList
、サブクラスにLinkedList
実装されており、特定のListIterator
サブクラスListItr
オブジェクトを作成します。
あるのでiterator()
方法、なぜ提供listIterator()
それを行う方法を?これら2つの方法の機能の重複はありますか?なぜわざわざ?Iterator
インターフェースで定義されているメソッドが少なすぎるため、これらの3つのメソッドを介してのみ実現できる3つしかなく正向遍历
、時には集約オブジェクト逆向遍历
で操作を実行する必要があるため、ListIterator
逆トラバースに使用されるhasPrevious()
合計はJDK インターフェースで宣言されますprevious()
他のメソッドの場合、クライアントがこれらの2つのメソッドを呼び出してリバーストラバーサルを実装する必要がある場合、このiterator()
メソッドを使用してイテレーターを作成することはできません。これは、現時点で作成されるイテレーターオブジェクトにこれらの2つのメソッドがないためです。続きを読むjava.util.ListIterator
オープンソースプロジェクトでのパターンの適用
トラバースがオープンソースプロジェクトで使用される場合、イテレータ設計パターンが多くの場所で使用されます。ここで1つだけ言及してくださいorg.apache.kafka.clients.consumer.ConsumerRecords
。詳細は、kafka client
ソースコードに記載されています。
public class ConsumerRecords<K, V> implements Iterable<ConsumerRecord<K, V>> {
@Override
public Iterator<ConsumerRecord<K, V>> iterator() {
return new ConcatenatedIterable<>(records.values()).iterator();
}
private static class ConcatenatedIterable<K, V> implements Iterable<ConsumerRecord<K, V>> {
private final Iterable<? extends Iterable<ConsumerRecord<K, V>>> iterables;
public ConcatenatedIterable(Iterable<? extends Iterable<ConsumerRecord<K, V>>> iterables) {
this.iterables = iterables;
}
@Override
public Iterator<ConsumerRecord<K, V>> iterator() {
return new AbstractIterator<ConsumerRecord<K, V>>() {
Iterator<? extends Iterable<ConsumerRecord<K, V>>> iters = iterables.iterator();
Iterator<ConsumerRecord<K, V>> current;
public ConsumerRecord<K, V> makeNext() {
while (current == null || !current.hasNext()) {
if (iters.hasNext())
current = iters.next().iterator();
else
return allDone();
}
return current.next();
}
};
}
}
}
モードの概要
イテレータパターンは、非常に頻繁に使用されるデザインパターンです。イテレータを導入することにより、データトラバーサル関数を集約オブジェクトから分離できます。集約オブジェクトはデータの格納のみを担当し、トラバースデータはイテレータによって完成されます。多くのプログラミング言語クラスライブラリにはすでにイテレータモードが実装されているため、実際の開発では、JavaやC#などの言語で定義されているイテレータを直接使用するだけで済みます。イテレータは、集約オブジェクトを操作するための基本になっていますツールの1つ。
- 主な利点
反復子パターンの主な利点は次のとおりです。
(1)さまざまな方法で集約オブジェクトのトラバースをサポートし、同じ集約オブジェクトで複数のトラバーサルメソッドを定義できます。イテレータモードでは、元のイテレータを別のイテレータに置き換えるだけで、トラバーサルアルゴリズムを変更できます。新しいトラバーサルメソッドをサポートするように、イテレータのサブクラスを定義することもできます。
(2)イテレーターは集約クラスを単純化します。イテレータの導入により、元の集計オブジェクトでデータトラバーサルなどのメソッドを提供する必要がなくなりました。これにより、集計クラスの設計を簡略化できます。
(3)イテレーターモードでは、抽象化レイヤーの導入により开闭原则
、要件を満たすために元のコードを変更せずに、新しい集約クラスとイテレータークラスを追加すると非常に便利です。
(4)実装がどのように変更されても使用でき、Iterator
導入Iterator
後にトラバーサルを実装から分離できます。トラバーサルでは、hasNext()
sum next()
メソッドのみを使用できます。基になるデータストレージ構造が変更された場合(たとえば、元のList
ストレージが使用され、要件がMap
ストレージを使用するように変更された場合)、上位の呼び出し元に対して完全に透過的です。トラバーサーは、どのように格納するかを気にしません。
- 主な欠点
イテレータパターンの主な欠点は次のとおりです。
(1)イテレータモードはデータの格納とデータのトラバースの責任を分離するため、新しい集約クラスを追加するには、それに応じて新しいイテレータクラスを追加する必要があります。クラスの数はペアで増加し、システムの複雑さがある程度増加します。 。
(2)設計の難易抽象イテレータ大、完全な組み込みのJDK反復子として、アカウントにシステムの将来の拡張を取る必要があるIterator
必要が逆方向移動を実装する場合のみ、そのサブクラスによって、達成することができない逆方向移動をListIterator
実装するなど、およびListIterator
反復コントローラーはSet
、操作タイプの集約オブジェクトには使用できません。イテレータをカスタマイズする場合、包括的な抽象イテレータを作成するのは簡単ではありません。
- 該当するシーン
反復子パターンは、次の状況で検討できます。
(1)内部表現を公開せずに、集約オブジェクトのコンテンツにアクセスします。集約オブジェクトへのアクセスを内部データのストレージから分離することで、集約オブジェクトへのアクセスに内部実装の詳細を理解する必要がなくなります。
(2)集約オブジェクトに対して複数の走査メソッドを提供する必要があります。
(3)異なる集約構造をトラバースするための統一されたインターフェースを提供し、インターフェースの実装クラスで異なる集約構造に異なるトラバーサルメソッドを提供すると、クライアントはインターフェースを均一に操作できます。