[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[jfriends] Re: インターフェースについて




前橋です。

>初めまして、大石と申します。

はじめまして。

>最近、Javaを勉強し始め、ようやく簡単なプログラムは組めるようになりました。
>しかしながら、いまいちインターフェースの使い道が分からず困っています。
>自分でインターフェースを記述して、インプリメントする事のメリット、若しく
>は、こんな時にインターフェースを使用すれば、効率よくプログラムを作成でき
>る等、ありましたら教えていただけないでしょうか。

遠藤さんの舌なめずりする音が聞こえてきそうな(^^;
...と思ってたのになかなか反応がないですね。

# 仕事中のメイルが禁止されたというオチでないことを祈ります。

私がJavaの勉強を始めた頃、入門書を何冊か読んだわけですが、
どれを読んでも、「Javaには多重継承がありません。だから、イン
タフェースを使います」的な書き方ばかりで、

  じゃ、インタフェースってのは、多重継承の貧乏人バージョンか?

などと思ったものです。

今に至って、色々考えると、多重継承を使うところって実はそうな
いような気もしてたりするのですが。

当時、読んだ本で、「なるほど」と思った例は、

「一歩先行くインターネット Java入門」とかいう感じの書名の本
にあった、自動車とガソリンタンクの例でした。

乗り物から、自動車やら自転車やらを継承する、というのは、割と
よくある例なのですが、さらに、ガソリンスタンドで給油できるク
ラスを考えた場合、

乗り物→ガソリンを使う乗り物→乗用車
                            →トラック

という継承関係にすると、

  じゃあ、ガソリンタンクを担いでガソリン買いに行っちゃいけないの?

ということになってしまいます(ガソリンタンクは断じて乗り物で
はない)。

こういう場合、

(1)「給油可能」インタフェースを作成し、
(2)給油可能な乗り物は、「ガソリンタンク」をメンバに持ち(コンポジション)
(3)かつ、「給油可能」をimplementsして、そのメソッドで、「ガ
  ソリンタンク」にガスを入れるようにする。

わけですね。

件の本では、ここで説明が止まっています。んで、ここまで見ると、
多重継承を使っても良さそうに見えます。

インタフェースとコンポジションで実現すると、「給油可能」メソッ
ドの実装は、単に「ガソリンタンク」の「給油」メソッドを呼ぶだ
けになっちゃって、それを書くだけ面倒くさいようにも思えるので
す。多重継承があれば良かったのに。やっぱり、インタフェースっ
て多重継承の貧乏人バージョンか?

でも、継承ってのは、あくまで、is aの関係が成り立つ時に使い、
has aの場合はコンポジションで、という考え方に基けば、この例
はあくまで

「自動車」 has a 「ガソリンタンク」

であって、

「自動車」 is a 「ガソリンタンク」

ではなさそうです。

「自動車はガソリンタンクである」

と考えるより、

「自動車はガソリンタンクを保持しており、給油のためのインタフェー
  スもあるよ」

と考える方が、多分自然です。

自然なだけでなく、

・ガソリンタンクをふたつ持った車
・俺の車のガソリンタンクを新型に付け替えた

などの時、多重継承では対応できませんが、インタフェースなら可
能です。ガソリンタンクがふたつあっても、給油メソッドで、まだ
空いてる方に注げばいいのです。

長くなりましたけど、まず、これが、

◎コンポジションと組み合わせる使い方

ですね。

他には、

◎複数の実装が考えられる場合

たとえば、ちょっと前に「オセロゲームの設計はどうあるべきか」
というネタをこのMLに投げたんですけど、

OthelloWindowを実現する手段としては、AWTを使ってもいいですが、
Swingを使っても、Java2Dを使っても、コマンドラインインタフェー
スを使ってもいいわけです。

こういうときは、OthelloWindowをクラスにしないでインタフェー
スにしておけば、OthelloWindowのメソッドを呼ぶ人を全然修正し
ないで、実装を差し替えることができます。

OthelloWindowを実装するクラスをnewして、オブジェクトの構造
(ポインタの張り合い)を作ってやるところまで、変更すればいいわ
けです。

この手は、「実装がまだない場合」にも使えそうです。グループで
プログラムを開発する場合、クラス毎に分担してコーディングする
のでしょうが、あるクラスのメソッドを呼ぶ人は、そのクラスのコー
ディングが完全に終了するまで書き始められない... のでは困ります。
こういう場合、先にインタフェースだけ書いとけば、それを呼ぶ人
は、まずコンパイルまではできますし(よね?)、テストする時には、
スタブ(ダミールーチン)の固まりのクラスで、そのインタフェース
をimplementsすれば良いわけです。

◎インタフェースが分類できる場合

あるクラスには10個メソッドがあるんだけど、この人が呼ぶのはそ
のうち1個だけじゃん、という場合、インタフェースに切り出せば、
関係が明示できます。

先のオセロの例だと、Board(オセロ盤)とJudge(審判)がいるんです
が、Judgeさんが知らなければならないメソッドは小数なので、イ
ンタフェースを分けました。

井浪さんのメイルにあった、自販機の例もそんな感じですね。

◎関数へのポインタ代わり

JDK1.1から、イベントモデルが変更になって、xxxListenerでイベ
ントを受けるようになりました。これは、たとえばC言語なら「関
数へのポインタ」を使うところです。

「ボタンが押されたら、このメソッドを呼んでね」

と、ボタンに対して事前に登録しておくわけです。

Javaではメソッドへのポインタはとれないので、イベントを受信す
るインタフェースを持つ(implementsしている)オブジェクトを登録
してます。

# これまた継承を使っても実現できるんですが。

他にも使用例はあると思いますが、Java初心者の私が、さっと説明
できるのは、この程度(^^;

------------------------------------------------------------
  前橋 和弥                             maebashi@xxxxxxxxxx
  中部ソフトエンジニアリング(株)
    〒450 名古屋市中村区名駅4-10-25(名駅IMAIビル 5F)
    Tel:(052)583-4511(代) 内線 252 Fax:(052)583-4566
------------------------------------------------------------