私はこれについて理解を深めようとしていますが、確かに唯一知っているのは、IteratorがJavaのインターフェースであることです。
ここ や ここ などのCS資料を読んで、同様の質問をここで探しています。
私が思いついたのは、少しわかりにくいだけです。たとえば、「抽象データ型は、操作の名前とタイプを要約するだけです(Javaでは、これはインターフェースを意味します)」または "各ADTはクラス(またはJavaインターフェース)に対応し、ADTの操作はクラス/インターフェースの操作です。パブリックメソッド "。ADTと抽象クラスを混同する人もいます。
では、イテレータは抽象データ型であると言えるでしょうか?
これについてはインターネット上で多くの混乱がありますが、この用語は非常に専門的であり、Cook paper (Greg Burghardtが好む answer で参照)によれば、それは本質的にこれに要約されます。
OOPオブジェクト(および関連する静的型付けメカニズム(クラス、抽象クラス、インターフェース型を含む))とADTは、データの抽象化に対する2つの異なるアプローチを表します。クックはOOPアプローチ「手続き的抽象化」を呼びます-私は後でそれに戻ります。2つは異なる長所と短所を持っています。
これを理解するには、基礎となる具体的なデータ構造(representations)、それらに対する操作、およびクライアントコード(これらの操作を呼び出す)について考えてください。 OOPアプローチを使用すると、一連の操作を変更しない限り、新しい表現(新しい派生クラス、またはインターフェースの新しい実装)を簡単に追加できます。この用語はpublic interface。これをinterface types(interface
キーワードで宣言)と混同しないでください。このより広い意味では、公開インターフェースはパブリックメンバーのセット(パブリックメソッド、プロパティ、フィールド、イベント)一方、新しい操作を追加することは困難です。既存のすべての異なる派生物を探し出し、それらの実装の詳細を変更して、それらすべてが変更されたインターフェースをサポートすることを確認する必要があります。
これは、パブリックインターフェースがクライアントとさまざまな実装の間のコントラクト、つまり呼び出されている実際の関数(プロシージャ)を抽象化するコントラクトを定義するという意味で「手続きの抽象化」です。インターフェイスは、操作のより一般化された概念を定義します-それはwhat操作meansを定義しますが、それはdoesですが、厳密にはではありませんどのようにそれはそれを行います。より抽象的な型の変数を介してオブジェクトのメソッドを呼び出す場合、(このコントラクトで定義されているように、ドキュメントで説明されているように)この操作を実行することが期待されますが、どれが確実かはわかりませんクラスが呼び出される具体的な関数-基本となる言語メカニズムが呼び出しをディスパッチします。
さて、ADTの場合は少し異なります。通常、有限のlimited一連の異なる表現(異なる基礎となるデータ構造)があります。これらはすべて、同じ抽象データ型(ADT)の異なる形式であると見なされます。これらの異なる具体的なデータ構造を、すべて同じタイプであるかのように使用できるように配置しているという意味では、抽象的です。これまでのところ、OOPとそれほど違いはないようです。以前と同様に、クライアントコードは具体的な表現に言及しません(コンストラクターが呼び出された場合を除く)。すべて、このADTに基づいて記述されています。ただし、ADTの演算ではない自体は同じように抽象化しますOOP演算はそうです。各ADT関数は、すべての可能な表現の実装を内部的に提供します。基本的にそこにswitchステートメントがあり、具象型をオンにします。そうでない場合は、ほぼ同じことを行う言語機能があります。したがって、ADTでは、クライアントは実際の具象タイプ(コンクリート表現)を無視できます各関数には、特定の表現を処理する部分があるため、機能することが保証されています。
これにより、新しい操作を簡単に追加できます。新しい関数を追加し、可能な表現ごとに少しのロジックを記述するか、既存の関数に依存してデータを抽象的に処理します。ただし、前述の保証に違反するため、新しい表現を追加することは困難です。それを維持するには、ADTのすべての関数を見つけ、新しいケースのサポートを実装する必要があります。
つまり、具体的な表現はクライアントコードから隠されていますが、(新しい操作を追加するための)拡張に関しては、ADTコントラクトの一部でもあります。
他のデカップリングと同様に、どちらの場合も、2つのコンポーネント間の特定のコントラクトを表す抽象化がその間にあります。それらは分離されます正確な理由両方とも、そのコントラクト、抽象化(2つのコンポーネント間の相互作用のより一般化された表現)に結合されます。契約が破られると、デカップリングも破られます。
関数型言語ではADTに遭遇しますが、表現の「切り替え」はパターンマッチングによって行われます。ただし、float
のようなプリミティブ型も、少なくとも特定の操作のコンテキストでは、ADTと見なすことができます。これは、基になる表現が異なるためです。 特殊 -inf、+ inf、NaNなどを表すビットパターンがあり、通常の算術演算を使用する場合、これらの特殊なケースを調べる必要がないため、演算で処理できます。これらだけで。
ただし、型システムがすべてではありません。これらのアイデアを使用して、型システムの外で独自の抽象化を設計できます。 1つの例は Visitor パターンです。これは複数のディスパッチを行う方法として説明されることが多いですが、ADTの実装と見なすこともできます。異なるElement派生物は異なる表現であり、異なるVisitorsは異なる操作です。類似点に注意してください。新しい訪問者を追加するのは簡単ですが、各訪問者がすべての要素を処理するため、新しい要素を追加することは困難です。それを行う別の方法は、ハンドルまたはオブジェクトまたは具体的なデータ構造の代わりに、操作がhandle(たとえば、ある種のインデックス)を受け取る操作を記述することです。これを内部的に使用して具象型を発見し、どこかでデータ構造を見つけます。これはおそらく、特別な状況下で行うことです。たとえば、キャッシュの使いやすさを確保するためにデータの格納方法を制御してパフォーマンスを向上させることが動機になる場合があります。
最後にあなたの質問に答えます。 Javaで実装されているイテレーターは、この意味でADTではありません。しかし一般的には、ADTとしてイテレータを実装することが可能であるべきです。
これは、ここで使用されている抽象化のkindが原因です。これは「手続き型抽象化」です(OOP抽象化の一種)): Iterator インターフェースは、「反復可能なもの」(コレクション)を表し、特定の抽象演算のセット(最も重要なのは、next
およびhasNext
)。
新しい表現を追加するのは簡単(イテレータの新しい実装)-インターフェースを実装するだけです。ここで、「新しい表現」とは、イテレータが内部で保持している状態や、反復についての正確な詳細などを指します。反復するコレクション、その順序、方法Iteratorインターフェースのみに依存している限り、クライアントコードに変更を加える必要はありません。 Javaのforeachループ(「強化されたforループ」)は、舞台裏でイテレーターを使用します。 Iterable インターフェースを実装している場合、カスタムコレクションで動作します。これにより、foreachループにイテレーターを取得する方法が提供されます。
さらに言えば、Javaが新しいコレクションと新しいイテレーター(イテレーターの新しい具体的な表現)を思いついた場合)は、他の人のコードに影響を与えません-それは人々が新しいオプションにすぎないということです必要に応じて利用できます。一方、foreachループをrequire Iterableインターフェースの新しい操作に変更した場合(ここでは、合理的なデフォルト実装がないと想定しています)、それは重大な変更になるでしょう-foreachループのサポートを提供するためにIterable&Iteratorを実装した人は誰でも戻ってコードを変更する必要があります。 1つはプログラマにとってもう1つ不便ですが、特に変更に直面した場合のクライアントコードとライブラリコード間の相互作用について、特に後者が「そこに」リリースされた後のことです。新しい実装は新しい動作を追加しています。しかし、それは抽象的なオペラの範囲内にありますons(概念的には同じ高レベル操作のセット)であり、クライアントコードはexpect thisのように記述されています。
では、イテレータは抽象データ型であると言えるでしょうか?
ADTは、データの集合と、そのデータに対して実行できる一連の操作です。イテレータは、反復する一連のデータと、その反復を実行するための一連の操作で構成されます。重要なのは、これらの操作はオペレーターの実行方法を定義しないことです。つまり、イテレータ(一般的には)はADTです。
しかしタイトルの質問への答え、「「A Javaイテレータは抽象データ型です」というのは本当ですか? ? "、is" no "。Java Iterator
はインターフェイスです。つまり、コレクションではなく、操作のセットのみを定義します。そして、一般的に、「Javaイテレータ」はそのインターフェースの実装なので、動作の実行方法を定義しますが、ADTではなく、抽象的ではありません。
正しいADTはabstractタイプです。つまり、どの言語でも表現または実装されていません。 Javaインターフェースは、紙、机の上、またはUMLダイアグラムの一部として記述または描写された、いくつかの可能な抽象イテレーターの特定の表現です。
しかし、Java.util.Iteratorは、可能なIteratorがどうあるべきかを非常によく表しています。他の多くの言語には、イテレータの別の表現があります。 Cppにはstd ::があり、最も一般的なケースのイテレーターです。イテレータは、私たちが概念として話しているものであり、議論できるものです。これは、特定の言語での日常業務で使用するものではありません。さらに、ADTまたは他の何かとして特定の構成要素でsmthを呼び出すことができるかどうかは問題ではありません。期待どおり機能するはずですこれですべてです。 Javaイテレータは本来すべきことを行います。そして、名前や用語については誰も気にしません。
ADTについて他に言えることは、それが現代のコンピューターサイエンスの時代遅れの概念であるということです。 ADTは、プログラムエンジニアリングの1つの側面(データの操作)のみを扱います。これは、より高いレベルの抽象化を介してすでに実装および再利用されているものに関するすべてです。今日では、データ抽象化は、主にコンピューターシステムの1つのレイヤー(DAO、データアクセスオブジェクト)でのみ使用されています。他のレイヤーは、主に他のタイプの抽象化、たとえばアクター、プロセス、戦略と連携します。したがって、既存のコードベースで数十年にわたって数千の実装が既に存在する抽象化の名前付けについて議論することは、生産的ではありません。