導入
同じ機能を持つクラスで、中身が異なるクラスを作る必要がある場合があります。その例が前回の内容でした。単純に複数の独立したクラスを作る方法もありますが、そのコードを継続的にメンテナンスしていく必要がある場合や、もっと大きなソフトウェアを作る場合には、それら複数のクラスが間違いなく同じように取り扱えるよう管理する手間が生まれます。仕様書をきちんと作成し、プログラマがその仕様書を守っていれば良いのですが、人間それほど「几帳面」な生き物ではありません。そこで考えられたのが今回学習するインターフェイスという仕組みです。インターフェイスにはさらに便利な使い方がありますが、今回は最も基本的な部分に絞って学習します。
展開
工夫の必要が生まれる
前回の学習の流れを次に示します。
- 設定情報が記載されたテキストファイルを読み込むクラスを作ろう。
- クラス1ができた。
- 別の方法でテキストファイルを読み込みたい。では別のクラスを作ろう。
- クラス2ができた。
クラス1とクラス2は同じ結果を得られるのですが、中身は別の仕組みを持っています。これら2つのクラスを使うクラス3からは、どちらのクラスも同じように使えるように作りました。
小さなコードでしたので困りませんでしたが、もっと大きなコードを書くときには、矛盾無くクラスを書くことに努力が必要になります。そこで、矛盾無くクラスを書くための工夫をする必要が生まれました。
インターフェイスを利用する
前回は「設定情報が記載されたテキストファイルを読み込む」という目的のもと、実装の異なる2つのクラスを作りました。今後も実装方法を変更する必要が生じる見立てがあるとか、異なる記載方法の設定ファイルを読み込む必要があるなど、実際のソフトウェア作成においては、プログラマは柔軟な対応を必要とします。
今回の場合はメソッドを呼ぶ方法と得られる情報が同じでしたから、設定情報を読み込む働きをする複数のクラスの「窓口」は共通です。この共通した窓口部分を切り出した機能を持つコードをインターフェイスと呼びます。インターフェイスは窓口となるメソッドと、定数の宣言部分のみを持ち、実装コードを持ちません。インターフェイスに記述されたメソッドを、プログラマが作成するクラスに組み込みコードを記述することをインターフェイスを実装すると呼びます。
似たような働きをするプログラミング言語の機能に抽象クラスがあります。抽象クラスはインターフェイスと同じ機能に加えて、必要ならば実装のあるメソッドを持てます。出生順からすると抽象クラスがお兄さんなので、学習の手順としては抽象クラスを先に学ぶべきなのかもしれません。しかしながら、この連載は「実践的」であることを旨としていますので飛ばしてしまいます。インターフェイスの機能は、次の理由から実用的なのです。
- 継承はトラブルメーカーなので、あまり使いたくない。
- 抽象クラスは複数継承できない。インターフェイスなら複数実装できる。
- 窓口を共通にする仕事のためにはインターフェイスで十分。
「複数継承」とは、正式な用語では多重継承と呼びます。多重継承とは複数のクラスを一度に継承することで、便利なのですが問題を生じやすい技術です。Java言語ではその問題を回避するために、あえて多重継承を許可していません。
先々も便利に使えるインターフェイスの最も基本的な使い方、窓口を共通にする機能をこれから使ってみましょう。
共通部分をインターフェイスに切り出す
詳しいインターフェイスの記述方法は参考文献等を読んでもらうとして、ここでは実際に切り出して作成したインターフェイスのコードを掲載します。
現実的・実用的にはフィールドCONFIG_FILENAME
はインターフェイスに記載すべきではないと思いますが、記述例として使用します。そしてメソッドはメソッド名のみを記載します。これによってバージョン番号の文字列を取得するためのメソッド名はgetVersion
であるとはっきりしました。このメソッドは必ず実装しないとコンパイルできませんから、プログラマにこのインタフェイスによる規約を守らせることができます。ConfigInfo
インターフェイスを実装するクラスにloadVersionString
というメソッドを別に作ることはできますが、getVersion
メソッドは必ず実装しなければなりません。共通の情報を取得するためのメソッド名がクラスによって異なるのは、それらのクラスを使うプログラマにとって悪夢でしかありません。インターフェイスに宣言されたメソッドを使いましょう。
インターフェイスConfigInfo
を実装したクラスのsketch AppInfoLoader3.pde
と、テストコードを次に示します。テスト用のコードがこれまでのものと全く同じであることを読み取ってください。
なお、テストコードに使用されるAppInfoLoader.pde
とAppInfoLoader2.pde
は前回第15回で作成したファイルです。同じスケッチフォルダにコピーを置いてください。
インターフェイスは実装を強制する道具
こうしてインターフェイスを使うのであれば、定数フィールドCLASS_NAME
も共通です。ただし値がクラスごとに異なりますので、メソッドに変更しましょう。そのほうが便利になります。インターフェイスにシグネチャgetClassName
を追加しましょう。そして具体的な値は実装時に与えるわけです。こうして、クラス名を取得するメソッドを実装する義務が生じました。今ここに、先ほどのAppInfoLoader3.pde
のタブを加えて実行しようとしても、AppInfoLoader3
クラスはConfigInfo
インターフェイスのgetClassName
メソッドを実装していませんからエラーを発生し実行できません。
インターフェイスにメソッド追加の変更が生じると、このインターフェイスを実装するすべてのクラスでそのメソッドを追加し実装しなければなりません。インターフェイスは滅多なことで変更すべきではないことが分かります。別の見方をすると、これは利点です。このインターフェイスを利用するすべてのクラスについて、もれなく変更しないと実行できませんから、うっかり修正忘れを防げます。ものは考えようで、良い方に考え、良い方に活用できるよう心がけましょう。
インターフェイスは代理窓口
インターフェイスは、そのインターフェイスを実装したクラスのインスタンスへの参照を持つことができます。これを簡単に表現すれば、インターフェイスが代理窓口の役目を果たしてくれるということです。
次のコードを読んでください。インターフェイスConfigInfo
を実装する、異なる二つのクラスAppInfoLoader4
とAppInfoLoader5
のインタフェイスを ConfigInfo
インターフェイスのインスタンスa
に代入しています。ConfigInfo
の実装部分のテストをするコードは同じですから、このようにインタフェイスを引数として渡すメソッドを書けば、同じコードで別のクラスのテストができてしまうというわけです。
ConfigInfo.pde
は先ほどのものと同じです。
TestAppInfoLoader3.pde
のメソッドtest
やメソッドtestAppInfoLoader
を読んで便利さを感じましたか? これは実際にデザインパターンを学んだときに真価を実感します。楽しみにしておいてください。
演習
演習1(難易度:easy)
設定ファイルCONFIG.TXT
が存在しない場合は、バージョン番号0.0を返すようにAppInfoLoader5
クラスを変更しましょう。新しいクラスのファイル名をAppInfoLoader6.pde
としてください。また、テスト用のsketchファイル名はTestAppInfoLoader4.pde
としましょう。sketchフォルダdataディレクトリにあるCONFIG.TXT
のファイル名を_CONFIG.TXT
などとして、わざと例外を発生させましょう。
演習2(難易度:easy)
インターフェイスConfigInfo
に設定ファイルを指定するメソッドを追加しましょう。メソッド名は動作を分かりやすく表すものにしてください。CONFIG.TXT
ばかりでなくSETTING.TXT
などというファイル名の設定ファイルも読み込めるようにします。これを実装するクラスをAppInfoLoader7
とし、AppInfoLoader7.pde
というファイル名で保存しましょう。テスト用のsketchファイル名はTestAppInfoLoader5.pde
としましょう。AppInfoLoader7
のインスタンス生成時にはデフォルトでCONFIG.TXT
を読み込みましょう。
まとめ
- 実装を強制するためのインターフェイスの使い方を学習しました。
- インスタンスを切り替えるためのインターフェイスの使い方を学習しました。
学習の確認
それぞれの項目で、Aを選択できなければ、本文や演習にもう一度取り組みましょう。
- 実装を強制するインターフェイスの役目が理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、今ひとつスッキリしない。
- 理解できない。
- インスタンスを切り替えるためのインターフェイスの役目が理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、今ひとつスッキリしない。
- 理解できない。
参考文献
- 『Java言語プログラミングレッスン(下)』(結城浩 著、ソフトバンククリエィティブ株式会社)
- Java言語のオブジェクト指向的特徴を大変分かりやすく解説した入門書中の名著。上下巻ともにJava言語入門者は必携。特に下巻はJava言語でオブジェクト指向を学ぶ入門書として最優秀。
演習解答
- 以下のファイルをsketchフォルダ
TestAppInfoLoader4
に納めます。
- 以下のファイルをsketchフォルダ
TestAppInfoLoader5
に納めます。