デザインパターンシリーズの反復子パターン-集約されたオブジェクトの要素に対する反復

説明:記事のデザインパターンシリーズは読むことです刘伟書かれた《设计模式的艺术之道(软件开发人员内功修炼之道)》ノートを読むために本を。個人的にはこの本はとてもいいと思いますし、読んでみたいです。詳細については、この本の著者のブログを確認することもできhttps://blog.csdn.net/LoveLion/article/details/17517213ます。

モードの概要

パターン定義

ソフトウェア開発では、一連のデータを格納するために集約オブジェクトを使用する必要があることがよくあります。集合オブジェクトには2つの役割があります。

  1. データを保存する
  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部との関係を示します。

Javaコレクションフレームワークの部分クラス構造図

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. 主な利点

反復子パターンの主な利点は次のとおりです。

(1)さまざまな方法で集約オブジェクトのトラバースをサポートし、同じ集約オブジェクトで複数のトラバーサルメソッドを定義できます。イテレータモードでは、元のイテレータを別のイテレータに置き換えるだけで、トラバーサルアルゴリズムを変更できます。新しいトラバーサルメソッドをサポートするように、イテレータのサブクラスを定義することもできます。

(2)イテレーターは集約クラスを単純化します。イテレータの導入により、元の集計オブジェクトでデータトラバーサルなどのメソッドを提供する必要がなくなりました。これにより、集計クラスの設計を簡略化できます。

(3)イテレーターモードでは、抽象化レイヤーの導入により开闭原则、要件を満たすために元のコードを変更せずに、新しい集約クラスとイテレータークラスを追加すると非常に便利です。

(4)実装がどのように変更されても使用できIterator導入Iterator後にトラバーサルを実装から分離できます。トラバーサルでは、hasNext()sum next()メソッドのみを使用できます。基になるデータストレージ構造が変更された場合(たとえば、元のListストレージが使用され、要件がMapストレージを使用するように変更された場合)、上位の呼び出し元に対して完全に透過的です。トラバーサーは、どのように格納するかを気にしません。

  1. 主な欠点

イテレータパターンの主な欠点は次のとおりです。

(1)イテレータモードはデータの格納とデータのトラバースの責任を分離するため、新しい集約クラスを追加するには、それに応じて新しいイテレータクラスを追加する必要があります。クラスの数はペアで増加し、システムの複雑さがある程度増加します。 。

(2)設計の難易抽象イテレータ大、完全な組み込みのJDK反復子として、アカウントにシステムの将来の拡張を取る必要があるIterator必要が逆方向移動を実装する場合のみ、そのサブクラスによって、達成することができない逆方向移動をListIterator実装するなど、およびListIterator反復コントローラーはSet操作タイプの集約オブジェクトには使用できませんイテレータをカスタマイズする場合、包括的な抽象イテレータを作成するのは簡単ではありません。

  1. 該当するシーン

反復子パターンは、次の状況で検討できます。

(1)内部表現を公開せずに、集約オブジェクトのコンテンツにアクセスします。集約オブジェクトへのアクセスを内部データのストレージから分離することで、集約オブジェクトへのアクセスに内部実装の詳細を理解する必要がなくなります。

(2)集約オブジェクトに対して複数の走査メソッドを提供する必要があります。

(3)異なる集約構造をトラバースするための統一されたインターフェースを提供し、インターフェースの実装クラスで異なる集約構造に異なるトラバーサルメソッドを提供すると、クライアントはインターフェースを均一に操作できます。

おすすめ

転載: www.cnblogs.com/itwild/p/12731108.html