clock2015.08.03 08:30
SERVICE
home

インターフェースとは?~継承とは役割が違う~|オブジェクト指向プログラミング(OOP)をおさらいしよう(3)

AUTHOR :  岩谷 和男

「インターフェース」を理解する上で「継承」の事は忘れてください

こんにちは。技術チームの岩谷です。前々回前回とオブジェクト指向プログラミング(OOP)をおさらいする連載を書かせていただいています。今回は第三回として、前回の継承機能と並んでOOP言語が持つ特徴的な機能の一つである「インターフェース」について説明します。私は最初にJavaに触れた時に「継承とインターフェースの違い」に戸惑いましたが、それはインターフェースの役割を理解していなかった事が原因でした。今回の記事で私は皆さんにそれをお伝えしたくて、あえて極端な表現を用いながら説明させていただきます。

まず申し上げます、

  • インターフェースを理解する上で、とりあえず「継承」の事は忘れてください。
  • 「インターフェースと継承との違い」を考えないでください。これが頭にあると理解の邪魔になってしまうのです。

インターフェースは「このクラスは、○×△メソッド(≒関数)を持ちます!」という「約束」です

まずインターフェース機能を使用するサンプルソース3つを以下に用意しました。ここではインターフェースの文法のみを説明しますので、このサンプルソースの処理の中身については気にしていただく必要はありません。また、このような短いサンプルでは「インターフェースを利用する事のメリット」はまったく発揮されません。よって、みなさんは「コードの文法はわかったけど…、で?何がおいしいの?」という疑問を今は忘れていてください。

まず、Javaで書かれた「インターフェース」のソースです。

 

次にこのインターフェースとひもづける※「クラス」のソースです。※ひもづけることを「実装する」といいます。

 

最後に上記の「インターフェース」と「クラス」を実際に使うクラスです。みなさんがサンプルソースとしてこれらのソースをコピペした場合、実際にみなさんが実行する対象として指定するクラスです。

 

ここで、注目していただきたいのは2つめのクラス「SampleClassAAA」のメソッド「doSomething」のメソッド名を何かほかの名前に変更した場合、「コンパイルエラーが起きる」という事実です。理由は、クラス「SampleClassAAA」が2行目でインターフェース「SampleInterface」の実装(ひもづけ)を宣言しているからです。これは何を意味するのでしょうか?答え(ソース2行目の意味)は以下の通りです。

私「SampleClassAAAクラス」はインターフェース「SampleInterface」の中に宣言してあるメソッド(≒関数)を全て持つことを「約束」します!この場合SampleInterfaceにはdoSomethingメソッドが定義してあるので、私もdoSomethingメソッドを必ず持ちます!「約束」します!もしこの「約束」を破ったらエラーを起こします!

という事を意味しているのです。この「約束」がインターフェースの本質です。これを「メソッドの実装強制」といいます。

この「約束」は何の為?今はまだ存在しない「未来に作られるプログラムたち」の為の約束です

このインターフェースの約束は何のために存在するのでしょうか?約束をすることで何かいい事があるはずです。ここでは先に答えを述べます。

インターフェースによるメソッドの実装強制という約束をすることで、「今現在、存在するプログラム」が「今はまだ存在しない未来に作られるプログラム」を利用する事が出来るのです。

意味がわかりにくいかもしれません。例を挙げて説明させてください。動画再生ソフトです。動画再生ソフトは動画ファイルを入力ファイルとして読み取って画面に映像を表示します。ここで気にしていただきたいことが二つあります。

まず一つ目として、「動画ファイルにはいろいろな形式がある」ということです。代表的な形式としては「H.264」「WMV」「RealVideo」などがあります。動画再生ソフトはこれらさまざまな形式に対応した動画再生能力を持つべきです。

さらに二つ目として、動画再生ソフトに求められる操作機能は、

  1. 動画・音声の再生
  2. 停止
  3. 一時停止
  4. 早送り
  5. 早戻し

といったように「ある程度”約束”されている」ということです。

これら2点によって動画再生ソフトは、「形式ごとの動画データを読み取るプログラム」と「読み取った動画データを操作する(再生・停止など)プログラム」に分割されているのです。以下にイメージを示します。ifimple

左側に「動画操作プログラム」があります。これが「今現在、存在するプログラム」だと思ってください。上記サンプルソースでいうとの3つ目の「SampleRun」に該当します。つづいて右側に「動画データ読み取りプログラム」があります。これらのプログラムは各動画形式に応じて個々に存在します。上記サンプルソースでいうとの2つ目の「SampleClassAAA」に該当します。ここで右下薄紫の箇所にご注目ください。

「近い未来、私こと岩谷和男がXXXXX形式という新しい動画形式を発明した!!」とします。(ありえね~汗)

この場合、XXXXX形式の動画を再生するために「動画再生ソフト」全体に大きなプログラム変更が必要なのでしょうか?世界中の「動画再生ソフト」に大きな改造を施さなければこの新しいXXXXX形式という動画はみんなに見てもらえないのでしょうか?答えはNoです。大きなプログラム変更は必要ありません。具体的には

  • ①.岩谷もしくは他の誰かが、右下薄紫の箇所の「XXXXX形式用動画データ読み込みプログラム」を新しく開発してインターネット上で公開する
  • ②.世界中の「動画再生ソフト」の利用者はそのプログラムをダウンロードして「動画再生ソフト」に”部品追加”する

という負担の少ない行為で動画再生ソフトはXXXXX形式の動画を再生する機能を獲得できます。イメージ左側の「動画操作プログラム」に変更を加える必要はないのです。

これを実現するのが「OOPにおけるインターフェース機能」なのです。①で新しく開発された「XXXXX形式用動画データ読み込みプログラム」にインターフェースを実装する(ひもづけする)事でこのプログラムは「メソッドの実装を約束する」事になります。上記イメージではインターフェース「VideoPlayer」のメソッド「play・stop・pause・foward・rewind」を持つことを「約束」するのです。そして「動画操作プログラム」はインターフェースであらかじめ「約束」されたメソッドを実行して動画に対する操作を行います。これによって「今現在、存在するプログラム」が「今はまだ存在しない未来に作られるプログラム」を利用する事が出来るのです。

Note:
この説明で「ん?上記②でいう、”部品追加”ってどうやるの?これができなければ機能が利用できないよね?」という疑問をお持ちになった方もいらっしゃると思います。これには「リフレクション」というOOPの機能を利用します。この「リフレクション」についての説明は少々複雑なのでまたの機会とさせてください。ご興味のある方はGoogleでキーワード「java リフレクション 文字列 インスタンス クラス」を指定して検索してみてください。「名前が事前に決定していないクラス」をプログラム内に読み込む方法を知ることができます。

インターフェースの役割は「ふるまい」の共通化です。コードの再利用ではありません

今回は連載の第三回としてOOPの持つインターフェース機能について説明させていただきました。長い文章になってしまいましたが、おつきあいくださってありがとうございます。ここまでお読みくださった方にはインターフェースという機能が継承とは異なる役割で存在する事がお分かりいただけたと思います。それは前回の継承機能で数多く言及した「コードの再利用」というキーワードが本記事で登場しなかったことからも明らかです。本記事ではメソッド(≒関数)という言葉を多用しましたが、メソッドはOOPの世界では「ふるまい」という言葉で表現されます。インターフェースはこの「ふるまい」を共通化する事を役割とする機能なのです。

追伸

本記事ではインターフェースの役割を端的に説明させていただくために作為的に継承機能とのかかわりあいを伏せて執筆させていただきました。「多重継承の代替」や「ポリモルフイズム」「リフレクション」といった考え方を今回は説明していませんが、今後ご要望をいただけるようでしたら執筆をさせていただきたいと考えています。…その際にはおそらく今回よりも複雑な説明になるかもしれません、その時はご容赦ください(笑)。

【本連載について】
SERVICE