質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

  • C#

    7714questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • .NET Framework

    489questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

  • オブジェクト指向

    298questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

なぜインターフェースICollection<T>が存在するのですか?

解決済

回答 2

投稿

  • 評価
  • クリップ 5
  • VIEW 2,027

askyq

score 19

C#で、オブジェクト指向を勉強しています。
以前から疑問に思っていることがあり、質問させていただきます。

ICollection<T>とCollection<T>を分離する理由が分かりません。
Collection<T>だけでもいいのではないでしょうか?

インターネットでいろいろ調べてみましたが、納得できる理由が分かりません。
MSDNにあるガイドラインのどれにも適合していないように思います。

・いくつかの値型を含む型のセットによって一定の共通機能をサポートする必要がある場合は、インターフェイスを定義してください。
・マーカー インターフェイス (メンバーを含まないインターフェイス) の使用は避けてください。
インターフェイスの実装である型を少なくとも 1 つ提供してください。
・定義した各インターフェイスを使用するメンバー (インターフェイスをパラメーターとして受け取るメソッドやインターフェイスとして型指定されたプロパティなど) を少なくとも 1 つ提供してください。
・既に提供済みのインターフェイスにはメンバーを追加しないでください。

MSDN「インターフェイスのデザイン」より)

・値型のポリモーフィックな階層構造を提供する必要がある場合は、インターフェイスを定義してください。
・多重継承と同様の効果を実現する場合は、インターフェイスを定義するようにしてください。

MSDN「クラスまたはインターフェイスの選択」より)

また、MSDN「抽象化の実装用の基本クラス」を読む限り、インターフェースはむしろ実装を煩雑化しているのではないかとさえ思えます。

その一方で、.NET Frameworkにおいては、ICollection-Collectionのみならず、IAsyncResult-AsyncResult、IList-Listといった、インターフェースと実装のペアがいくつか見られます。
このようなペアは、一見実装を煩雑化させているように見えます。
わざわざこのようなことをしている理由について、私なりに考えてみましたが、これくらいしか思い浮かびませんでした。

  • コンポジションを利用してあるクラスをコレクションとして振る舞わせたい時に、ICollection<T>はその実装を保証(具体的に言うとキャスト可能にする)するだけでなく、クラスにCollection<T>以外のクラスを継承することを許可する
  • 実装を持たないインターフェースを提供することにより、コレクションの内部振る舞いを完全に隠蔽かつ抽象化する。例えば、データを内部で配列として保持しようがマップとして保持しようが、同一のインターフェースからコレクションを利用可能にする(実際、Dictionary<K,V>はICollection<KeyValuePair<K,V>>を実装しています)

前述の理由が認められるならば他のすべてのクラスにもインターフェースとのペアを作らなければいけないと思ったのですが、ICollectionなどは、.NET Frameworkにおいて極めて重要なクラスであるため、特別に定義と実装を分離しているように思えます。
しかし、本当に重要度が高いのが理由なのでしょうか?

ICollectionとCollectionのように、わざわざ定義と実装が分離されたインターフェース・クラスのペアが複数存在する理由について、皆様のお考えと、もしあれば実例をお聞きできないかと思い、質問いたします。
オブジェクト指向について初歩的な質問で申し訳ありませんが、どうぞよろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+3

ICollection<T>とCollection<T>を分離する理由が分かりません。 

委譲のときに、委譲元の参照から委譲先の実装を分離するためです。Collection<T> を使いたい人が、 ICollection<T> 型で参照することで、いつでも Collection<T> を他のものと入れ替えることができるようになります(厳密には入れ替えやすくなります)。

たとえば、ある日、Collction<T> の性能問題が出て、コレクションの中身がプロジェクト特有のデータ特性を持つことが原因だったとします。それで Collection の実装を少し変更することで、その性能問題を解消できる場合、  ICollection<T> を実装する MyCollection<T> というクラスを作成し、Collection<T> と入れ替えることができます。もし、 Collection<T> を直接参照していると、その参照箇所を修正する必要があります。委譲元を開発している人と、委譲先を開発している人が別人の場合を想像してください。インタフェースを参照することで、クラスを直接参照するより、結合度を下げることができます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+2

同じオブジェクト指向言語でも、
C++みたいに多重継承を許す言語もあれば、
C#、Javaみたいに多重継承を許さない言語が存在します。

質問者様も抜粋してます、
MSDNの「クラスまたはインターフェイスの選択」の説明が今回の肝で、
コアな部分では何故インターフェースファーストの開発が行われるかの大きな理由となってきます。

仮に.NET FrameworkにICollection、IListが存在しないと仮定してみましょう。

単純にICollectionやIListと構造がほぼ同じのCollection、Listクラス辺りから見ると、
「インターフェースとかなくても問題ないじゃん」と思いがちです。

ですがCollection定義構造をそのままもつ他のクラス(適当にHogeCollectionとします)を実装することを考えると話が変わってきます。

C#ではインターフェイスでなければ
多重継承のような仕組みを再現できない
ため、
もし上記のように他のクラスを作成する場合、
Collectionクラスを継承して機能拡張したクラスにしなければなりません。
更にこのクラス機能群をそのまま利用するクラスが必要・・・となると、
一瞬で継承の泥沼にハマります。
(コアな部分ではこういったことが多々あるため、
インターフェイスがないと多分えらいことになるでしょう。)

むしろこのような作りとなっている各クラスの継承階層を追う方がしんどい・・・と思いませんか?

更に言うと上記は、
オブジェクトの相互変換性が皆無となります。
例えばCollectionとHogeCollectionをどちらもCollectionの機能範囲だけで操作したいという場合、
インターフェイスがなければ実現が困難です。
(当方レベルと代替案が思いつきませんでした。)

ですがインターフェースを事前に用意されていると、
Collection、HogeCollectionどちらにもICollectionを実装することで、
どちらもICollection型経由でのアクセスが可能となります。
これで呼び出し側をシンプルに出来ますね。

おまけにこれは質問者様も把握しているかと思いますが、
1つのクラスが複数のインターフェイスを実装していることで、
この時は読み取り専用のオブジェクトとして振舞わせたいとか柔軟な利用方法が可能になります。
(例えばListクラスはIList、IReadOnlyListインターフェイスを実装してるからどちらのデータ型としても利用可能となります。)

上記に書いてきたような事情もあって、
インターフェイスを定義した後に、
各抽象クラス、クラスにて必要な分を実装するという方法が王道となっています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/22 21:06

    分かりやすい解説をありがとうございます。

    おっしゃるとおり、C#では多重継承ができないので、コレクションのような振る舞いをする別のクラスを作成するのが困難ですね。
    コンポジションでいいじゃん、と思ったのですが、そもそもインターフェースがあるの前提の話です。
    知らないうちに、インターフェースの恩恵に与っていたのかもしれません。

    .NET Frameworkのドキュメントを見ててさっき気づいたことですが、
    ICollectionがなければ、当然IDictionaryもなくさないと整合性がとれませんよね、
    DictionaryはCollectionを継承することになりますが、その時点でCollectionの実装がすでに入っていますので
    Dictionary用に最適化されたロジックを新たに作ることができない(使う側を混乱させる)問題も出てきます。
    .NET Frameworkのコア部分ではそういったこともよく起こるということ、理解できました。

    ありがとうございました。

    キャンセル

  • 2017/01/22 22:34

    > askyqさん
    フレームワークのコア部分に近づけば近づくほど、
    mit0223さんの回答で述べられている「結合度を下げる実装」というのは重要です。

    インターフェイスベースで疎結合を保つことで、
    より安全に機能の差替えが行えるからです。

    何度もテコ入れされ得る場所には、
    予め蓋をしておこうということですかね。

    そういった意味では、
    オブジェクト指向を学ぶ上でフレームワークのソース・作りを参照するのは有益かもですね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C#

    7714questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • .NET Framework

    489questions

    .NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

  • オブジェクト指向

    298questions

    オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。