JAVAを勉強している者です。説明が下手ですいませんが、「インターフェース」って何のメリットがあるんですか?
「インターフェース」は
「派生化してその目的に特化したそれぞれのクラスを統一しておくことでそれらのクラスを気にしなくても、使うことができるもの」
とか
「派生化したそれぞれのクラスが、その中身を気にしなくても統一して利用できるようにするためのもの」(説明が下手ですいません。)
らしいですが、そんなことして何のメリットがあるんですか?開発が短縮されるんですか?
バラバラな(派生化してその目的に特化した)クラスを統一するなら、最初からきちんと完璧に設計すれば早いと思うのですがどうでしょうか?
**わかりやすいような例や例えで教えてくれませんか? **
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答17件
0
既に回答が出揃ってる感ありますが、少しでもお役に立てればと思ったので回答させていただきます。
僕も初学の際に同じような疑問を持っていたので、僕なりにわかりやすくお伝えできればと思います。
前提
以下のようなアプリケーションであればインターフェースを利用するメリットはほとんどありません。
- 一人で開発するアプリケーション
- 一度作って終わる(作った後一切変更をしない)アプリケーション
- レイヤ化(MVC等)する必要のないアプリケーション
故に、上記に当てはまらないアプリケーション開発をイメージして説明させていただきます。
(ほとんどこのケースですが・・・)
説明
何のメリットがあるんですか?
インターフェースの実装が増えても利用者はそれを意識せず形式的に利用できるというメリットがあります。
詳細は、例を踏まえて後述します。
開発が短縮されるんですか?
上記のメリットがあるので、長期的な目線で見ると短縮されることがあります。
ただし、一度作って終わるものはファイルを余計に作成するだけなので逆に開発が延びます。
バラバラな(派生化してその目的に特化した)クラスを統一するなら、最初からきちんと完璧に設計すれば早いと思うのですがどうでしょうか?
将来的に起こりうる変更を予測して、おっしゃるように「最初からきちんと完璧に設計」できるのであれば、それに越したことはありません。
わかりやすいような例や例えで教えてくれませんか?
一般的に、インターフェースとは「契約」と言われることが多いです。
日常生活で身近な契約って何だろて考えたときに、電力会社との契約とかがわかりやすいかなと思います。
電力会社と契約済みであれば、極端ですが「電気ちょーだい」というと電気が供給されると思います。
この時、供給された電気はどこでどのように生み出されたのか意識したことはありませんよね?(原子力発電なのか、火力発電なのか、風力発電なのか)
そして、もしかしたら、将来的に原子力発電は廃止されて、それに変わる新たな発電方式が生み出されるかもしれません。その場合でも今まで通り「電気ちょーだい」というと電気が供給されるはずです。
このように、**利用者は、契約(インターフェース)によって、電源(実装)を意識しなくても、形式的に電気(メソッド)を利用することができます。**これがインターフェースの主な存在意義だと思います。
では具体的に、その考え方がどのように実装に活かされるのかを、簡単な例になりますが見ていきましょう。
TODO管理のアプリケーションをチーム(複数人)で開発する場面を想像してみてください。
- まず、TODOのデータを保存する場所を考える必要がありますよね。
最初は、開発スピード等を重視して、この保存先にローカルのファイルを選んだとしましょう。
0. 次に、少なくともリクエストをコントロールする「クラスA」と、ローカルのファイルに対してTODOデータをCRUDする「クラスB」を実装すると思います。
※ここでは「クラスA」と「クラスB」との間にインターフェース(契約)を設けないでアプリケーションを作り上げたとします。
0. リリース後、ユーザーが順調に増え、アプリケーションがまともに動かなくなってきました。
0. スケーラブルな構成への変更を余儀なくされ、データの保存先をローカルのファイルから、クラウドのRDBMSへ移行することを決めます。
0. そして、誰かがRDBMSに対してTODOデータをCRUDする「クラスC」を実装しようとします。
ここからが悲劇の始まりです。
過去に誰かが実装した「クラスA」は「クラスB」からデータをもらう前提で実装されています。
今回の変更で「クラスA」は「クラスB」ではなく「クラスC」からデータをもらうことになるので「クラスC」の実装・テストに加え「クラスC」の実装を知った上で「クラスA」の修正・テストも必要になります。
せっかく責務を分離してクラスを分けていたのに、結局クラスAへの影響も大きそうですね。。。
もし、最初から「クラスA」と「クラスB(TODOデータをCRUDするクラス)」との間にインターフェース(契約)があれば、今回も「クラスC」がそのインターフェースを実装することによって戻り値の型は保証されるので「クラスA」は「クラスC」の実装を知る必要がありません。
そして多くの場合「クラスA」にほとんど影響はありません。
また、この先NoSQLに対してCRUDを行う「クラスD」、新型のDBに対してCRUDを行う「クラスE」・・・が現れても「クラスA」と「TODOデータをCRUDするクラス」との間にインターフェース(契約)があるかぎり「クラスA」はそのクラスの実装を全く意識する必要はありません。
「クラスA」は「クラスB〜E・・・」がどんな実装をしてどこからデータを取ってこようが、それらのクラスが契約通りに実装してくれれば「クラスA」に変更が加わることは原則ありません。
以上、簡単な例でしたが前述の通り、役割ごとにカテゴライズされた各レイヤー間にインターフェース(契約)を設けることによって、各レイヤー間を疎結合にし(依存度を低くし)、変更に強いアプリケーション作ることができる
これがインターフェースを利用する最大のメリットと言っても過言ではないと思います。
#####補足
インターフェースのメリットを最大限に活かす仕組みとしてDependency Injection(依存性の注入)というデザインパターンがあります。
少々複雑な上、質問に対する回答にはならないのでここでは触れませんが、インターフェースを理解された次のステップとして、知っておくと良いと思います。
投稿2017/03/25 21:22
編集2019/02/16 18:39総合スコア4258
0
ベストアンサー
未来のことを考えてください。
今完璧に設計しても、世の中の法律が変わるとかお客さんの要望が変わるとか、さまざまな要件でコードには見直しがかかるときがあります。
インターフェースとはそのときに備えておくためのものです。
こちらが参考になるかもしれません。
ここから具体例を書いてみましょう。長くなりますので読まなくても構いません。
家電製品を考えてみます。
【問題になるようなパターン(インターフェースなし)】
1.ドライヤーを作った
2.電子レンジを作った
3.冷蔵庫を作った
それぞれは共通のコンセントを持っていますので、一つの電源タップで利用することができるとします。
4.新しい電化製品、テレビが発明された。
ここでこのテレビという製品は、新製品であるがためにコンセントの形が独自に作られていたとします。
そうすると従来の電源タップで使うことができません。変換機を買ってきたり、場合によっては家を工事する必要があるとします。
せっかくの新製品なのに、うまく使えず家庭の皆さんはさぞ怒ったことでしょう。また売るほうとしても工事が必要とあっては売れ行きに響くかもしれません。
これがインターフェースが統一されていないということです。
【上記問題を解決するようなパターン(インターフェースあり)】
0.コンセントの規格が決まり、電化製品は基本的にはその規格に沿ったコンセントを作る必要があることになった(インターフェース)
1.ドライヤーを作った
2.電子レンジを作った
3.冷蔵庫を作った
4.テレビが発明された
ここで上記の家電製品のコンセントの形が全て統一されていれば、全て同じ電源タップが使えますね。変換機を買ってきたり、工事をしてコンセントの形を変えたりなどということは不要になります。
逆に言えば、家電製品の開発者は「コンセントの形を統一する必要性に迫られる」ということになりますが、それがインターフェースの本質です。
CDを買ったことはありますか?いろんなレコード会社から出ているCDは、統一されたCDプレイヤーで聴くことができますね。それはCDというインターフェースに合わせて各会社がCDを作っているからです。何もCDプレイヤーを買いなおす必要はないわけですが、それは各会社がわざわざ努力している賜物です。
AndroidとiOSは充電に使うケーブルの形が違いますね。あれは規格が違うからです。ユーザーからすれば、統一されていたほうが便利だと思いませんか。企業戦略ゆえ仕方のないことですが、2本も使い分けしたりしたくはないですね。
投稿2017/03/25 17:40
総合スコア1947
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
実は僕も、(欠点は多いですが)「多重継承でいんじゃね?」と思ったことがあります。
まずインタフェースのインプリメントと、クラスの継承の違いから考えると。
クラスの継承は、そのクラスの本質的な機能を受け継ぐことです。
対して、インタフェースの実装はそれ以外の機能を参照するための「口」を作ることです。
実のところ、デリゲーション(移譲)モデルを理解しないで、インタフェース継承だけ使っても旨味は薄いです。
というか、C++の多重継承とどう違うのかさえ理解しづらいです。
さらに言えば、インタフェースは継承した側から見れば「機能の拡張」ですが、参照する側から見れば余計なメソッドや属性をいじらせないための「機能の制限」(=他の人のコメにも書いてある通り「疎結合」ってやつですね)と言う側面もあります。まさに「インタフェース」です。
そういった事が理解できた頃から「なるほど合理的だ」と思えてきたものです。
投稿2017/03/28 05:41
編集2017/03/28 05:46総合スコア18
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
私の答えは恐らく少数派で、反論が出ると思いますが... Jave,C#は多重継承がないのでインターフェイスが必要だったのではないかと考えています。逆に、多重継承があれば、インターフェイスは要らなかったのではと考えています。
コンセントの例でしたら、抽象クラスでも同じことが出来るわけですし。なぜ、Javaに多重継承がないのかが疑問です。
投稿2017/03/28 04:22
総合スコア75
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/03/28 06:19 編集
2017/03/28 07:00 編集
2017/03/28 14:45
2017/03/29 04:12
2017/03/29 08:46 編集
0
例:コンセントとプラグ
世の電源プラグが規格がバラバラだったとして、
この部屋のコンセントは、とある掃除機の電源プラグにしか適合しません。
別の部屋のコンセントは、とあるテレビの電源プラグにしか適合しません。
などと言われたら不便ですよね?
そこで電源プラグにインターフェースを定義してやれば
コンセント側は何が刺さっているかは気にせずに電力供給できるようになりますね。
もちろん最初からちゃんと"設計"して、ここにはこの機械しか置かないと決めれば
インターフェースがなくても問題ないですが、
これが賃貸住宅などだったら柔軟性がなくて使う側が困りますね?
基礎的な仕組みだけ提供し、後は使う側が決めてくださいというときに
インターフェースは役立ちます。
プログラム的には、フレームワークなんかがそうですね。
例:加速度センサーをつかって歩数計を作る
加速度センサークラスなるものが存在するとして、
歩数計クラスは加速度センサークラスから値を取ってきて
いろいろ処理して歩数を計算するとします。
さて、不具合が起きたときの調査用に、
加速度センサーのログを模擬入力として歩数計を動かしたく思いました。
安直なのは歩数計クラス内に、
if(調査モード) acc = ログファイル.値を取ってくる(); else acc = 実機.値を取ってくる(); (歩数判定の処理)
などと書くことです。
しかし、これだと、歩数計クラスが歩数判定以外のことをしてしまい、コードの見通しが悪くなります。
そこで、加速度センサーインタフェースを作成し、
実際のセンサーと、ログファイルによる模擬はこのインターフェースを実装させます。
歩数系クラスはインスタンス作成時に
加速度センサーインタフェース(を実装したクラスのインスタンス)を渡せば
acc = センサー.値を取ってくる(); (歩数判定の処理)
と歩数計クラス内で歩数検知に関係ないコードが減ります。
投稿2017/03/25 13:00
総合スコア13551
0
ざっくりと説明すると、サービスを提供する側(ライブラリーなんかがそうですね)が、
「うちのサービスを使うときには、この『資格』を満たしてね!」
ということを、あらかじめ決めておくための仕組み、
って感じですかね。
資格を満たす=規定されたメソッドを実装する。
ですね。
同じようなことは、もちろん、クラスの派生でもできるんですが、
インターフェースのほうが、使いやすい場面があるということなんですね。
ちょっと、例え話での説明に挑戦してみます。
すべての動物が参加できる、オリンピックが開催されるとします。
それをシステムとして考えてみましょう。
(なんて例えだw)
オリンピックなんで、幾つもの競技があります。
100m走、水泳なんかは、人間界にもありますが、
全動物ですから、飛行競技だってあったりします。
100m走に出場するため『資格』は、「走れる」ことで、
(走る)という行動が取れることです。
水泳に出場するための『資格』は、「泳げる」ことで、
(泳ぐ)という行動が取れることです。
飛行競技に出場するための『資格』は、「飛べる」ことで、
(飛ぶ)という行動が取れることです。
オリンピック運営側(サービスを提供する側)は、
各競技ごとに必要な『資格』をあらかじめ決めておくことで、
どんな動物が出場できるかを提示することができますよね。
さて、次は、参加動物(サービスを利用する側)について。
それぞれの競技に参加できるのは「どんな動物か?」
「走れる」動物、「泳げる」動物、「飛べる」動物です。
鳥や、魚や、四足歩行、二足歩行、なんかで分類しようとすると、
ちょっと無理がありますよね。
例えば・・・
魚であるトビウオは、水泳に参加できる。
魚であるトビウオは、飛行競技にも参加できる。(ちょっと違うくない?w)
鳥であるワシは、飛行競技に参加できる。
ペンギンやダチョウは、鳥なのに、飛行競技に参加できない。(なんてこった)
四足歩行のチーターは、100m走に参加できる。
二足歩行のヒトも、100m走に参加できる。
鳥であるダチョウは、100m走には参加できる。(おお!)
鳥であるペンギンは、100m走には参加できる。(参加することに意義あり!)
鳥であるペンギンは、水泳にも参加できる(おお!!)
さあ、鳥はどうやって分類(汎用クラス)しましょう?
飛べる鳥、
飛べない鳥、
飛べないけど泳げる鳥、
飛べないけど走れる鳥、
飛べないけど走れて泳げるペンギン(笑)
もう、抽象化の意味がなくなってきそうですw
そこで、『資格』(インターフェース)ですね。
『資格』を特徴として考えて、
鳥「飛べる」
鳥「走れる」
鳥「走れる」「泳げる」
というように、より抽象的な鳥クラスを、それぞれの『資格』(インターフェース)で補足するほうが、
表現しやすそうです。
ペンギンは、鳥で、「走れる」「泳げる」『資格』を実装しているわけです。
さて、話をオリンピック運営側に戻します。
上記のように、それぞれの動物が、競技ごとに必要な『資格』(インターフェース)を実装しているわけですから、
100m走に参加する動物は、(走る)という行動がとれることが保障されています。
同じように、水泳や飛行競技に参加する動物も、(泳ぐ)、(飛ぶ)という行動が取れます。
ですので、オリンピック運営側は、参加動物に対して、(走れ)と号令をかけるだけで、100m走の競技を開始することができるわけです。
以上、自分の少ない知識を総動員させて、書いてみましたがいかがでしょうか?
きっと、インターフェースにはもっと高尚な効能がたくさんあるはずなのですが(正直、私のレベルではわかりませんw)、取り掛かりとしては、こんな感じがイメージしやすいように思います。
以前は、コードを重複させないよう、クラスの汎化にこだわりたくなってました。が、現実、設計に時間がかかりすぎることが多かったです(笑)そして、汎化した意味があまりなかった・・・なんてことも(笑)
クラスの汎化は、コード重複を減らすため、よりは、問題領域の概念を正しく表すこと、のほうが大事ですよね。
実装が多少散らばっても、早く動くものを作りながら、リファクタリングをしつつ、見えてきたものから抽象化していく、という流れが、現実的なのかな?と考えてます。
投稿2017/03/28 14:39
総合スコア715
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
小規模の開発であればインターフェースを実装するメリットはあまりありません。
インターフェースを利用するメリットはメンテナンス性の向上だと思います。
インターフェースは実装されるクラスによって実装方法は異なりますが、インターフェースを実装されたクラスではそのメソッドを見れば何の目的のメソッドなのかわかります。
インターフェース:泳ぐ
インターフェース:飛ぶ
インターフェース:走る
基底クラス:動物(食べる、寝る、遊ぶ)
↓
子クラス1:哺乳類
↓
孫クラス:ジャガー←インターフェース:泳ぐ、走る
基底クラス:動物
↓
子クラス2:カラス←インターフェース:飛ぶ
投稿2017/03/28 07:55
総合スコア20
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
実例で行きましょう。
Readableインターフェイスは、readメソッドを持つインターフェイスです。
これを継承するクラスは下記のものがあります。
BufferedReader, CharArrayReader, CharBuffer, FileReader, FilterReader, InputStreamReader, LineNumberReader, PipedReader, PushbackReader, Reader, StringReader
文字列を取得して処理するメソッドの引数には、Readableインターフェイスを指定すれば、上記のいずれのクラスであろうと、一つのメソッドで動作が可能です。
もし設計を頑張ってReadableクラスとしてすべての継承元のクラスを取り込んだ巨大なクラスを作ったとしたら、おそらくメンテが効かず、入力の形式が増えたときの対応は難しくなるでしょう。
また、StringReaderクラスにはCloseableインターフェイスがありますが、CharBufferクラスにはありません。
このような複雑な違いを吸収する設計を事前に行うには、相当の思慮とコーディングが必要になります。
もちろんインターフェイス設計を間違うと継承先のすべてのクラスに影響しますので注意が必要ですが、影響範囲を狭くすることで、設計の問題を少なくすることが出来ます。
投稿2017/03/25 13:33
総合スコア2883
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
わかりやすい例を挙げるなら、HTMLのDOMノードもよい例だと思います。
<DIV> <P> <BR> </DIV> <DIV> <A></A> </DIV>
HTMLの内部を調べる方法の一つにこれらのタグの階層をDOMとして表現し、そのノードを辿るということはよく行われます。DOMではDIV,P,BR,AなどのHTMLタグは全てElementというDOMノードで表現されます。その一つ下の階層を辿るにはElementインターフェースのchildというメソッドで辿れることになっています。(メソッド名などはクラスライブラリーによって違うかもしれませんがそのあたりは気にしないでください)
さて、Elementという共通のインターフェースがなかったとしたら・・・
DIV.getChildOfDiv
P.getChildOfP
A.getChildOfA
...
etc.
こういう似たようなことをするgetChildOfナンチャラメソッドを沢山用意し、今見ているノードの種類ごとに「一つ下の階層を調べる」コードを書くのに以下のような似たコードを大量生産しなければなりません。
switch (typeof(currentNode)) { case DIV: return ((DIV)current).getChildOfDiv; case P : return ((P)current).getChildOfP; case A : return ((A)current).getChildOfA; ... }
そんなことをするよりこれらの全てのノードはElementという共通のインターフェースを持つと定義して
currentNode.getChild
の1行で済ませてしまうことの方が優れた設計にできる・・・
こういったことがインターフェースの意義です。
投稿2017/03/25 12:39
総合スコア18400
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こんにちは。
らしいですが、そんなことして何のメリットがあるんですか?開発が短縮されるんですか?
開発期間の短縮効果は確実にあると思います。
Javaはあまり知りませんが、例えばC#は列挙できるクラスはIEnumerable<T>インタフェースを継承しています。多くはコンテナですね。
ある日、IEnumerable<T>を継承したコンテナを使って列挙処理を書いたとします。その人はそのためにIEnumerable<T>の使い方を学んだことでしょう。
その日以降、その人はIEnumerable<T>を継承したコンテナ全ての列挙処理を書けるようになります。
特に新人さんにとってはかなり有り難い話と思います。
また、クラスの外部インタフェースをドキュメントだけで記述するより、インタフェースを定義することで厳密に記述でき、かつ、強制も容易なため、再利用性の改善や結合テスト時の不具合削減効果もあると思います。
投稿2017/03/25 12:32
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
最初からきちんと完璧に設計すれば早い
これは理想論です。実際はなかなかその通りにはいきません。契約や設計初期における技術実働部門の発言権は大きくない場合が大半です。逆に、汎用的なユーティリティを作成する段階では、アプリケート側の都合を考慮しきれない場合もあります。
たとえば、ArrayListとLinkedListはどちらも可変長リストを実現しますが、向き不向きがあります。要素の追加削除が多いならばLinkedListの方が向いていますが、ランダムアクセスをするならばArrayListの方が向いています。このようば場合、プログラミングの段階においてはどちらにすれば良いのか確定しないことは多々ありえます。このような場合はインタフェースを使っておくと便利です。
投稿2017/03/25 11:28
編集2017/03/25 11:34総合スコア4830
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
最初からきちんと完璧に設計すれば早いと思うのですがどうでしょうか
まさに書いているじゃないですか?
しっかりと設計をする。
設計をしっかり守らせる。
守らせる為の制約手段ですよ。
多人数になると制約が必要になってくるものです。
メソッドのスペルミスなどもコードチェックの段階で回避できます。
投稿2017/03/28 04:46
編集2017/03/28 04:49総合スコア20
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
すでに接点としての回答が出揃っているので、別の観点での補足みたいな感じです。
javaで解説すると、インターフェースは質問者がおっしゃっている、「設計」です。
設計をきちんとするということは、インターフェースをきちんと作るということです。
インターフェースはインプリメンツしますが、インプリメンツには、
条例を施行する、規約を実施する、という意味があります。
クラスは実装ですから、インターフェースは設計、となります。
なので、設計がブレれば、実装もブレます。
完璧に設計できれば、実装も完璧かと思います。
オブジェクト指向言語は、
言語としての機能としてこれらを備えている、というところでしょうか。
投稿2017/03/28 23:59
編集2017/03/29 00:22総合スコア24
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
疎結合 というのが的確な答えなんですが、プログラムの
規模が大きくなると、インターフェースによる疎結合は
不可欠なものです。プログラムがモノリシックで複雑な化物に
なることを防ぐ有用な武器です。
オブジェクト指向である程度規模の大きなプログラムを組むにあたって
必要とされる基本原則の一つに、
IOC(Inversion of Control)
があります。多くのオブジェクト指向設計の本で詳細な
具体例が解説されていますで、それらを読むことをおすすめします。
投稿2017/03/28 14:40
総合スコア62
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/03/26 00:07
2017/03/28 05:44 編集