- ベストアンサー
なぜインタフェースを使うのか?
カテゴリはJavaですが、オブジェクト指向という観点での質問です。 私はオブジェクト指向を勉強中です。(C#) そこで、疑問に思ったのがタイトルで示したインタフェースについてです。 以下に疑問を列挙します。 1.インタフェースはなぜ使うのですか? 2.使うメリットはなんですか? 3.インタフェースのインスタンスって作れるのですか? 4.インタフェースは必ずどこかのクラスに継承されないといけないのですか? 単体では何もできないのですか? 5.具体的な使い方を教えてください。 全部でなくてもよいのでわかる方ご教授よろしくお願いいたします。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
インターフェースとは「役割」です。 一般的なインターフェースの命名規則は「~ableを末尾に付ける」とあります。例えば「比較できる」なら「ICompareble」です。 メディア再生ならplay,stop等を持ったIPlayableインターフェースが考えられます。これで動画、音楽、静止画が文字通り「再生できます」。 クラスは実装とインターフェースの両方を継承しますが、これでは不便なことが沢山あります。最も不便なのは、余計なメソッドが沢山付いてくること、多重継承でもしない限り、継承だけでは機能を共有しきれない(多重継承は多重継承で、別の問題がある)事です。 インターフェースにはこの制約がありません。「~ができる」という役割に必要なメソッド群を定義し、その役割を持たせたい複数のクラスに実装させれば良いのです。 また逆に、1つのクラスに複数の役割を持たせることができます。 インターフェースは、引数の型指定に使うと用途がよく分かります。 元のインスタンスが何を継承していようと、インターフェースを通じて操作できるのはそのインターフェースに定義されたメソッドだけ、つまり純粋に「ある役割について操作したい」というメソッドを定義できます。 1.インタフェースはなぜ使うのですか? 継承では制約が多い場面で、特定の「役割」に基づいた操作を定義したいとき、インターフェースを使います。 2.使うメリットはなんですか? 継承より制約が少ないことです。中身が空っぽというデメリットは、「委譲」で回避できます。委譲とは、実装済みのクラスに処理を委ねてしまう(単なるクラス呼出し)です。 3.インタフェースのインスタンスって作れるのですか? 作れませんが、インターフェースの引数や変数に、インターフェースを実装したクラスのインスタンスを代入できます。この辺の使い勝手は普通のクラスと同じです。 4.インタフェースは必ずどこかのクラスに継承されないといけないのですか? 単体では何もできないのですか? 中身がありませんし、それだけではインスタンス化できませんから、YESです。 5.具体的な使い方を教えてください。 理論的な話なら「Javaオブジェクト設計」というペーター・コード氏の著作をお薦めします。 C#での具体例なら、参考URLにプラグインの作り方が載っています。
その他の回答 (7)
- bobviv
- ベストアンサー率50% (13/26)
インターフェースの威力を知りたければ、たとえばストラテジ(Strategy)パターンと呼ばれているデザインパターンのサンプルコードなど一度ごらんになるとよいと思います。 細かいこと言うと、インターフェースが実現するポリモーフィズム(多態性)は、コンパイル時にはインターフェースSの型として型チェックされたオブジェクトが、実行時にはSを実装したクラスのインスタンスなら何でもよいという「ズレ」によって支えられています。インタフェースの効能はというと、 1.多態性(すでにご指摘の) 2.コントラクトが守られているかどうかをコンパイラによってチェックさせることができる。 3.単一のオブジェクトに対して、今問題にしたいひとまとまりの機能一覧を抽象して顕在化させることができる。この時特に「他のインタフェースや実装の詳細は”見えないし、見なくて済む”」 といった諸点にあると思います。 いずれにしろ、JavaやC#をお書きになるならインターフェースを理解しないっていう手はありません。その威力に触れたら、今とは逆にインターフェース中毒になってしまうくらい使いたくってしょうがなくなると思いますよ^^。
- unibon
- ベストアンサー率47% (160/340)
いろいろな考え方はありますが、私はつぎのような考え方をお勧めします。 要は、呼ばれることだけに特化した「インターフェース」の定義です。その使用方法を超えるものは class (abstract class も含む)にしたほうが良いです。 ただ、interface は「軽い」ので、コーディングの都合上、本来は class のほうがふさわしいのだけど、便宜上 interface にしてしまう、ということも多いです。 巷の書籍等の解説では interface を過度に使いがちな傾向があると思います。しかし、設計の開始時点では、まずは interface よりは abstract class を使うことを検討されたほうが良いです。その中から interface で済むものを、interface に「降格」させるような感じにすると良いでしょう。 > 1.インタフェースはなぜ使うのですか? クラスが呼ばれる際の呼ばれ方、および呼び側での呼び方、を定義するためです。 > 2.使うメリットはなんですか? 古いものにたとえると、C の関数ポインタのプロトタイプ宣言に、近いものになります。 interface がないと、コンパイル時にメソッドを呼ぶ時の引数の並びや引数の型が分からないままになってしまいます。実行時にこれらを解決する方法も考えられなくはないのですが、概して面倒になります。 > 3.インタフェースのインスタンスって作れるのですか? 呼ばれ方の定義だけですので、それだけではインスタンスは作れません。まあ、しいて言えば、 class FooClass extends Object implements BarInterface みたいなことをすれば良いわけですが。 > 4.インタフェースは必ずどこかのクラスに継承されないといけないのですか? > 単体では何もできないのですか? 呼ばれ方の定義なので、単体で使うということはないです。interface を使うからには呼ばれるクラスがあるはずなので、そのクラスが interface を implements します。 > 5.具体的な使い方を教えてください。 リスナ(listener)が interface の最たる使い方になります。 Button の ActionListener などです。
- ency
- ベストアンサー率39% (93/238)
他の方々の回答で、ほぼ出尽くしているとは思いますが。。。 > 1.インタフェースはなぜ使うのですか? > 2.使うメリットはなんですか? クラスの継承をいわゆる「is-a関係」のみに限定するためです。 決して「(クラスの)多重継承の代用品」ではありません。 (クラスの)多重継承に相当することをやろうとした場合、インタフェースによって同等のことができるためこのような言われ方をすることもありますが、本来の意味はもう少し違うところにあると思います。 > 3.インタフェースのインスタンスって作れるのですか? 作れません。 > 4.インタフェースは必ずどこかのクラスに継承されないといけないのですか? > 単体では何もできないのですか? インスタンスが作れないため、インタフェース単体では何もできません。 ちなみに、インタフェースは継承ではなく「実装 (implement)」という言葉を使いますね。 > 5.具体的な使い方を教えてください。 インタフェースを文字通りとらえれば良いのではないでしょうか。 たとえば、円を「描く」、三角形を「描く」、…といったように図形を「描く」という共通の「インタフェース」を用意する場合とか。 もちろん、図形というクラスに「描く」というメソッドを用意しておいて、それを継承するという方法も考えられます。 ここでよく考えてみてください。 「図形」というクラスの意味は何でしょうか。 ただ単に「描く」という操作のみのために、クラスを作る意味は本当にあるのでしょうか。 円を「描く」場合には、「中心座標から半径の距離にある点を結んでいく」という方法を取るのに対して、三角形を「描く」場合には、「三点の座標を順番に結んでいく」という方法を取りますよね。 つまり、「描く」という処理の「実装」方法が異なるわけです。 まさに「異なる処理を同じインタフェースで実装する」ことこそが、インタフェースの本来の姿なのです。 もちろん、他の要素を考えたときに「図形」というクラスが必要だということになるかもしれません。 そうするメリットが大きいのであれば、それでも良いと思います。 インタフェースは、「何でもかんでもクラスを作って継承させれば良い」といういい加減な設計をさせないための指標の一つであると言っても良いかもしれません。 インタフェースについては「Java には多重継承がないから、その代用品としてインタフェースが存在する」というような、いかにも Java の欠陥 (?) を補うものであるような言われ方をすることもあるようです。 しかし、わざわざクラスを新たにクラスを作らなくてもインタフェースで十分間に合うことも多いはずです。 いずれにしろ、設計段階でこのあたりの話を整理できていなければ、まともなプログラムにはならないと思います。 こんな感じで、いかがでしょうか。
- UKY
- ベストアンサー率50% (604/1207)
他の回答者より本質的な話をしてみたいと思います。 C# や Java は「静的な型付け」を行う言語です。「型」というのは、あるオブジェクトがどのようなメソッドやフィールドを持っているか、ということです。そして、静的な型付けというのは、コンパイルの時にプログラム内のオブジェクトの型が正しいかどうかを (ほとんど) 全てチェックすることを言います。 逆に、JavaScript はオブジェクト指向言語ではあっても「動的な型付け」を行います。動的な型付けを行う言語では、オブジェクトの型が正しいかどうかはプログラムが実際に実行されるときにチェックされます。動的な型付けを行う言語には、インタフェースという言語機能は普通は存在しません。 さて、C# は静的な型付けの言語だといいました。そこで、コンパイル時の型のチェックがどのように行われるか簡単な例をあげてみましょう。文字列から Substring メソッドで一部を取り出します。 string s = "abc 123 xyz"; string t = s.Substring(4, 3); ここで、変数 s に対して問題なく Substring メソッドが使えるのはなぜかを考えてみると、コンパイラはここで次のような三段論法を使っています。 1. 変数 s の型は string クラスである。 2. string クラスには Substring メソッドが定義されている。 3. よって、変数 s に対して Substring メソッドを呼び出すことが出来る。 したがって、コードを次のように書き換えるとコンパイルできなくなります。 object s = "abc 123 xyz"; object t = s.Substring(4, 3); なぜなら、「object クラスには Substring メソッドが定義されている」が成り立たないからです。 ここで、三段論法の一つ目の命題に注目してみます。 「変数 s の型は object クラスである。」 ここでは、オブジェクトの型は object というクラスによって規定されているので、object クラスで定義されているメソッド (ToString など) を変数 s に対して使うことはできます。しかし逆に言えば、object クラスで定義されていないメソッドは使えません。 上の例では、変数 s の実体は string オブジェクトであるにもかかわらず、object クラスという型に阻まれて、Substring メソッドを使えないわけです。 というわけで、静的な型付けの言語では、オブジェクトのメソッドやフィールドを使うためにはそのオブジェクトの型がとても重要なのです。 さて、上のコードでは string オブジェクトを object 型の変数に代入しました。つまり、子クラスのオブジェクトは親クラスの型の変数に代入することができます。 では あるクラスのオブジェクトをその「いとこクラス」の型の変数に代入できるでしょうか。残念ながらできません。子クラスのオブジェクトは親クラスのオブジェクトの振りをすることができますが、いとこ同士だとそうとは限らないからです。 では、遠い親戚 (または、赤の他人) 同士が同じメソッドを持っているときに、たとえクラスに親子関係がなくても 同じ型として扱うにはどうすればいいのでしょうか。 親子関係という制約があるのは、クラスによって型が決められているからです。そこで、クラスとは異なるものによって型を決めるようにすれば問題を解決できます。それがインタフェースです。 例えば、string クラスには CompareTo というメソッドがあって、二つの string オブジェクトを比較できます。また、int 構造体にも CompareTo というメソッドがあって、二つの int 値を比較できます。string クラスと int 構造体には親子関係はないので、そのままでは string のオブジェクトと int の値を同じ型で扱うことはできません。 しかし、どちらも CompareTo メソッドが使えるという点では共通しています。そこで、IComparable というインタフェースを作り、string クラスと int 構造体はそれぞれ IComparable インタフェースを実装するようにします。IComparable インタフェースには、「CompareTo メソッドがある」ということだけが書かれています。 こうすることで、クラスに親子関係がなくても、それぞれのオブジェクトを IComparable という一つの型で同じように扱うことができるようになります。
- thamansa
- ベストアンサー率40% (95/232)
インタフェースは、クラス間の依存性を低めることができます。 言い換えると、インタフェースを使うと、実装クラスがなくてもインタフェースを使うクラスを作ることができます。 例 AaaクラスがBbbクラスを使うプログラムを作るとします。AaaクラスがBbbクラスを使うとは、たとえば void foo(Bbb b)というメソッドがAaaクラスにあるということです。 また、Bbbクラスには void bar(int i) 見たいなメソッドがあって、foo() から bar() を呼び出すことになるとします。 このとき、Bbbがクラスである場合、Aaaのソースコードをコンパイルするには、Bbbクラスのコンパイルが終わっていなければなりません。 Bbbクラスが複雑で、開発に時間がかかる場合はダミーのBbbクラスを作らなければなりません。 では、Bbbをインタフェースにしたらどうでしょう。 Bbbは void bar(int i)の宣言だけでいいのですぐ作れます。 Aaaは、Bbbインタフェースがあるのでコンパイルもできます。テスト用には Bbbを実装した BbbStab スタブクラスでも作ればいいでしょう。 ダミークラスではないので、本物の実装クラスができたときに上書きする必要もありません。
- rinkun
- ベストアンサー率44% (706/1571)
もともとオブジェクトの継承には2つの側面があります。 その一つがインターフェースの継承であり、もう一つが実装の継承です。 classはこの継承の両方を実現しますが、interfaceはインターフェースの継承のみを実現します。 interfaceを使うのは多重継承の実現のためです。実装の継承を含めた多重継承の実現は言語仕様としてもコンパイラの実装としても複雑になり難しいため、これを避けるために多重継承はインターフェイスの継承のみとし、そのためにclassとは別にinterfaceを用意しています。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
C#の話(javaも概ね同じ)で(おおざっぱな話なので話半分で) 1.インタフェースはなぜ使うのですか? 2.使うメリットはなんですか? ・多態性を実現する ・抽象クラスを書くより記述が楽できる ・抽象クラスと違って多重実装、多重継承ができる 3.インタフェースのインスタンスって作れるのですか? インターフェースのインスタンスは作成できないが、 インターフェースをデータ型とする変数などを宣言することはできる。 (インターフェースを実装したインスタンスを代入でき同じメソッドを使用できる(多態)) 4.単体では何もできないのですか? 抽象メソッド(インターフェースとしてのメソッド)しか持たないので 実装されないでは、インスタンスも作れないし、何も(?)できない 5.具体的な使い方を教えてください。 面倒くさいので、 ここのサイトからインターフェースを使っているもの(java)を紹介 http://okwave.jp/kotaeru.php3?qid=1250952
お礼
ご回答ありがとうございます。 unibonさんだけでなく、他の方々にもこの場でお礼を言わせていただきます。 みなさんのお陰で、インタフェースの用途とか使う目的は分かってきました。 ありがとうございました。