Posted at
JavaDay 9

Javaにおけるインタフェースの使い道を今一度考える

More than 1 year has passed since last update.


はじめに

Javaのアドベントカレンダーに登録したはいいけれど特に新しい知見とかが思いつかなかったのでこれは知見の整理です。

これは宗教的なことわりなのですが、この記事では"interface"を全て「インタフェース」と表記します、ご了承ください。

鉞はご自由にお投げください。


インタフェースとは

文法的な部分は探せばどこにでも怪しい記事が転がっているので今更説明はしませんが、要素は確認しておきましょう。


  • インタフェースもクラスと同様に型として提供できる

  • インタフェースを実装しているクラスはインタフェースの持つメソッドを全て定義していることが保証される

  • メソッドのデフォルト実装(Java8以降)は提供できるがインスタンスは生成できない

語弊を恐れずに一言で言うと、特定のメソッドを持った型を定義できるものがインタフェースと考えていいでしょう。


1. ライブラリの外部公開する型として使用する

様々な理由により何らかのファクトリーメソッドでしかクラスのインスタンスを生成させたくない場合があります。

この場合、インタフェースにクライアントが使うべきメソッドを定義しておき、そのインタフェースだけを公開するという設計にすることはあります。

私の記憶が正しければ、Twitter4JはOAuthのトークンを取得するような場面でこのような形になっていたと思います。

複数人で開発する場合は、実際のクラスではなくクラス間を繋ぐコネクターとして外部構造だけ先に欲しいということもあるかと思います。

そのような場合に、インタフェースを定義しておくと作業者の間で連携が取りやすくなるという効果もあります。


2. 複数のクラスの共通部分を取って逐次的に処理する

ポリモーフィズムあるいは多相と言ってもいいんですが、あえてそのような単語は避けておきたいと思います。

例えば、ゲームなんかを作っていると何ミリ秒とかに一度共通の処理をしたいということがあります。

その際、Listなどに対象となるオブジェクトを全て突っ込んで処理したいと思うのはとても自然な感情です。ここに抽象クラスを導入すると変な継承関係ができて気持ち悪いなぁということになるかと思います。

そのような場合、適当なインタフェースを1つ実装しておけば全て事足ります。

Javaの標準ライブラリに沿って話をするのであれば、Runnableや、それにJava8から導入された関数型インタフェース(これはもっと汎用的な使い方ができますが)も大体このような使い方をしていると思います。


3. 実装を入れ替える必要がある場合の共通の型として使う

これはデザインパターンで言うとストラテジーパターンに相当するものです。

Javaの標準ライブラリの話を元に話をしたほうが早いと思うのでそうしましょう。

CollectionクラスにはListやMapなどのインタフェースとArrayList,LinkedList,HashMap,TreeMapといったインタフェースを実装したクラスがあります。これは当然メソッドを実行したときの内部状態やアルゴリズムが違うのでクラスが分かれている訳ですが、Listインタフェースを受け取るようなメソッドの場合、どんな実装かを気にする必要はそんなにないかと思います。

外部から与えられたアルゴリズムに従ってソートを行うためのComparatorもこれに近いですが、Java8からのComparatorは関数インタフェースとして扱われているのでこれは「引数にメソッド自体を指定する」ためのものと考えることもできます。


4. 関数オブジェクトの代替品として使う

これは一言で言えば「関数を第一級オブジェクトとして扱える」という話で、厳密にはJavaはそこまでのものは提供していないように思いますが今は置いておきます。

Java8最大の変更と言えば、インタフェースに関数型インタフェースという区分ができたことでインタフェースを関数オブジェクトの代替品として使えるようになったということではないでしょうか。

冒頭でインタフェースはインスタンスを生成できないと言いましたが、インタフェースを実装した匿名クラスとして宣言してインスタンス化する方法は取れました。Runnableインタフェースは特にこのような使い方をすることもあったと思います。

関数型インタフェースはラムダ式を用いることでこの冗長さをなくし、FunctionやConsumerなどの汎用的な関数型インタフェースを持たせることでインタフェースをメソッドの入れ物として使えるようにしました。

インタフェースをメソッドの入れ物として使えることで何が嬉しいかという話はここでは詳しく触れませんが、特に3で触れたストラテジーパターンはやりやすくなると思います。


おわりに

適当に思いついたものを書いたのでもっと色々あるかもしれませんが、思いついたら追記します。

あとサンプルコード作る気力がなかったので気が向いたら作るかもしれないです。