シーン
販売管理システムを開発するために、システムを分析、設計する際、システム内の製品データや顧客データを横断する必要があることがよくあります。
これらのトラバーサル コードを再利用するために、開発者は抽象データ コレクション クラス AbstractObjectList と、商品や顧客などのデータを格納するクラスを設計しました。
AbstractObjectList クラスのサブクラスである ProductList および CustomerList は、それぞれ製品データおよび顧客データを格納するために使用されます。
ソフトウェア開発では、一連のデータを保存するために集合オブジェクトを使用する必要があることがよくあります。集約オブジェクトには 2 つの役割があります。1 つはデータを保存することです。
2 つ目は、データを走査することです。依存関係の観点から見ると、前者は集合オブジェクトの基本的な責任ですが、後者は変更可能であり分離可能です。
したがって、データを走査する動作を集約オブジェクトから分離し、「イテレータ」と呼ばれるオブジェクトにカプセル化することができます。
イテレータは、集約オブジェクト内のデータを走査する動作を提供します。これにより、集約オブジェクトの設計が簡素化され、「単一責任の原則」の要件をより適切に満たすことができます。
イテレータパターン
反復子パターン:
オブジェクトの内部表現、つまりカーソルのエイリアス (Cursor) を公開せずに、集約オブジェクトにアクセスするメソッドを提供します。
イテレータパターンはオブジェクトの動作パターンです
イテレータパターン構造図
イテレータ パターン構造図には次の役割が含まれています。
イテレータ (抽象イテレータ):
要素にアクセスして走査するためのインターフェイスを定義し、データ要素を走査するためのメソッドを宣言します。
例えば:
最初の要素を取得するfirst()メソッド、次の要素にアクセスするnext()メソッド、他に要素があるかどうかを判断するhasNext()メソッド、
現在の要素などを取得するために使用される currentItem() メソッドは、特定のイテレータに実装されます。
ConcreteIterator (具体的な反復子):
これは、抽象イテレータ インターフェイスを実装し、集約オブジェクトのトラバースを完了し、特定のイテレータ内のカーソルを介して集約オブジェクト内の現在位置を記録します。
実装される場合、カーソルは通常、位置を表す非負の整数です。
集計 (抽象集計クラス):
これは、要素オブジェクトを保存および管理し、イテレータ オブジェクトを作成する createIterator() メソッドを宣言し、抽象イテレータ ファクトリとして機能するために使用されます。
ConcreteAggregate (具体的な集計クラス):
これは、抽象集合クラスで宣言された createIterator() メソッドを実装し、具体集合クラスに対応する ConcreteIterator インスタンスを返します。
注記:
ブログ:
Domineering Rogue Temperament_C#、アーキテクチャ ロード、SpringBoot-CSDN ブログ
成し遂げる
1. 新しい抽象集計クラスを作成する
import java.util.ArrayList;
import java.util.List;
//在本例中,为了详细说明自定义迭代器的实现过程,没有使用JDK中内置的迭代器,事实上,JDK内置迭代器已经实现了对一个List对象的正向遍历
//抽象聚合类
abstract class AbstractObjectList {
protected List<Object> objects = new ArrayList<>();
public AbstractObjectList(List objects){
this.objects = objects;
}
public void addObject(Object obj){
this.objects.add(obj);
}
public void removeObject(Object obj){
this.objects.remove(obj);
}
public List getObjects(){
return this.objects;
}
//声明创建迭代器对象的抽象工厂方法
public abstract AbstractIterator createIterator();
}
2. 新しい抽象反復子を作成する
//抽象迭代器
interface AbstractIterator {
//移至下一个元素
public void next();
//判断是否为最后一个元素
public boolean isLast();
//移至上一个元素
public void previous();
//判断是否为第一个元素
public boolean isFirst();
//获取下一个元素
public Object getNextItem();
//获取上一个元素
public Object getPreviousItem();
}
3. 新しい特定の集計クラス: コモディティ データ クラスを作成します。
import java.util.List;
//商品数据类:具体聚合类
public class ProductList extends AbstractObjectList{
public ProductList(List objects) {
super(objects);
}
//实现创建迭代器对象的具体工厂方法
public AbstractIterator createIterator() {
return new ProductIterator(this);
}
}
4. 特定のイテレータを作成します: 製品イテレータ
import java.util.List;
//商品迭代器:具体迭代器
public class ProductIterator implements AbstractIterator{
private ProductList productList;
private List products;
private int cursor1; //定义一个游标,用于记录正向遍历的位置
private int cursor2; //定义一个游标,用于记录逆向遍历的位置
public ProductIterator(ProductList list){
this.productList = list;
this.products = list.getObjects();//获取集合对象
cursor1 = 0;//设置正向遍历游标的初始值
cursor2 = products.size() -1 ; //设置逆向遍历游标的初始值
}
public void next() {
if(cursor1<products.size()){
cursor1++;
}
}
public boolean isLast() {
return (cursor1 == products.size());
}
public void previous() {
if(cursor2>-1){
cursor2--;
}
}
public boolean isFirst() {
return (cursor2 == -1);
}
public Object getNextItem() {
return products.get(cursor1);
}
public Object getPreviousItem() {
return products.get(cursor2);
}
}
5. クライアントへの電話
import java.util.ArrayList;
import java.util.List;
public class Client {
public static void main(String[] args) {
List products = new ArrayList();
products.add("商品1");
products.add("商品2");
products.add("商品3");
products.add("商品4");
AbstractObjectList list;
AbstractIterator iterator;
list = new ProductList(products);//创建聚合对象
iterator = list.createIterator();//创建迭代器对象
System.out.println("正向遍历");
while (!iterator.isLast()){
System.out.println(iterator.getNextItem()+",");
iterator.next();
}
System.out.println("逆向遍历");
while (!iterator.isFirst()){
System.out.println(iterator.getPreviousItem()+",");
iterator.previous();
}
}
}
6. まとめ
イテレータパターンは非常によく使われる設計パターンであり、イテレータを導入することでデータトラバーサル機能を集計オブジェクトから分離することができます。
集約オブジェクトはデータの保存のみを担当し、データの走査はイテレータによって行われます。多くのプログラミング言語のクラスライブラリはイテレータパターンを実装しているため、
したがって、実際の開発では、Java や C# などの言語で定義されたイテレータを直接使用するだけで済み、イテレータが操作になります。
オブジェクトを集約するための基本ツールの 1 つ。
イテレータ パターンの主な利点は次のとおりです。
(1) さまざまな方法での集合オブジェクトの走査をサポートしており、同じ集合オブジェクトに対して複数の走査メソッドを定義できます。イテレータモードで
走査アルゴリズムを変更するには、元のイテレータを別のイテレータに置き換えるだけで済みます。また、イテレータのサブクラスを自分で定義することもできます。
新しいトラバース方法をサポートするため。
(2) イテレータは集計クラスを簡素化します。イテレータの導入により、元の集計オブジェクトでデータ トラバーサルなどのメソッドを提供する必要がなくなりました。
これにより、集約クラスの設計が簡素化されます。
(3) イテレータ モードでは、抽象化層の導入により、元のコードを変更せずに新しい集計クラスやイテレータ クラスを追加することが非常に便利です。
「オープンクローズ原則」の要件を満たします。
イテレータ パターンの主な欠点は次のとおりです。
(1) イテレータ モードではデータの保存とデータのトラバースの責任が分離されるため、新しい集計クラスを追加するには、それに対応して新しいイテレータ クラスを追加する必要があります。
クラスの数はペアで増加するため、システムの複雑さがある程度増加します。
(2) 抽象反復子の設計が難しく、JDK 組み込み反復子 Iterator では逆走査が実現できないなど、将来のシステム拡張を十分に考慮する必要がある。
逆走査を実装する必要がある場合は、そのサブクラス ListIterator などを通じてのみ実装でき、ListIterator イテレータを使用して Set 型の集計オブジェクトを操作することはできません。
イテレータをカスタマイズする場合、包括的な抽象イテレータを作成するのは簡単ではありません。
次の場合には反復子パターンの使用を検討してください。
(1) 内部表現を公開せずに集合オブジェクトの内容にアクセスします。集約オブジェクトへのアクセスを内部データのストレージから分離することで、集約オブジェクトへのアクセスが可能になります
内部実装の詳細についての知識は必要ありません。
(2) 集約オブジェクトに対して複数のトラバースメソッドを提供する必要がある。
(3) 異なる集約構造を横断するための統一インターフェースを提供し、インターフェースの実装クラスで異なる集約構造に対して異なる横断メソッドを提供します。
クライアントはインターフェイスを一貫して操作できます。