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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

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

オブジェクト指向

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

.NET Framework

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

Q&A

解決済

2回答

6857閲覧

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

askyq

総合スコア46

C#

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

オブジェクト指向

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

.NET Framework

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

6グッド

5クリップ

投稿2017/01/22 07:32

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

Tak1wa, musix55, oriduru, nakasho_dev, yohhoy👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

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

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

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

投稿2017/01/22 09:05

mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

同じオブジェクト指向言語でも、
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 09:39

編集2017/01/22 09:48
Panzer_vor

総合スコア1636

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

askyq

2017/01/22 12:06

分かりやすい解説をありがとうございます。 おっしゃるとおり、C#では多重継承ができないので、コレクションのような振る舞いをする別のクラスを作成するのが困難ですね。 コンポジションでいいじゃん、と思ったのですが、そもそもインターフェースがあるの前提の話です。 知らないうちに、インターフェースの恩恵に与っていたのかもしれません。 .NET Frameworkのドキュメントを見ててさっき気づいたことですが、 ICollectionがなければ、当然IDictionaryもなくさないと整合性がとれませんよね、 DictionaryはCollectionを継承することになりますが、その時点でCollectionの実装がすでに入っていますので Dictionary用に最適化されたロジックを新たに作ることができない(使う側を混乱させる)問題も出てきます。 .NET Frameworkのコア部分ではそういったこともよく起こるということ、理解できました。 ありがとうございました。
Panzer_vor

2017/01/22 13:34

> askyqさん フレームワークのコア部分に近づけば近づくほど、 mit0223さんの回答で述べられている「結合度を下げる実装」というのは重要です。 インターフェイスベースで疎結合を保つことで、 より安全に機能の差替えが行えるからです。 何度もテコ入れされ得る場所には、 予め蓋をしておこうということですかね。 そういった意味では、 オブジェクト指向を学ぶ上でフレームワークのソース・作りを参照するのは有益かもですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問