JavaやC#にある、インターフェース(interface)のお話。
これがまた初心者にとっては一つの壁ですね。

新人君
新人君

そうそう。
クラスは何とかわかりましたが、インターフェースはちょっと…
インターフェースって要るんですか?

うん。なかなか理解できないよねぇ。

実を言えば、Javaが登場する前に一般的だったC++にはクラスしかないんです。

じゃあなんでJavaにはインターフェースがあるかというと、クラスだけでもプログラムは作れるんですが、複雑になりやすかった。
その複雑さを減らすために、用途を特化した形のクラスであるインターフェースが出来上がったのです。

ただその話題は大きなテーマなのでここでは扱わず、インターフェースの意味合いインターフェースのメリットについて、お話していきたいと思います。

「インターフェース」ってどういう意味?

UI(User Interface)の例

「インターフェース」という言葉の意味から把握してほしいのです。言葉の意味の意味が分かるとイメージしやすいから。

そもそも「インターフェース」とは何かというと

物と物との境界面、合わさる部分をインターフェースといいます。

現実にあるインターフェースはよく目にするものでいうと

  • USBの端子部分
  • 電源のコンセント
  • イヤホンジャック

これらは機械同士の境界面ですね。それ以外にも

  • UI(User Interface)

これは機械と人間とをつなぐもの。GUI/CUIなど、コンピューター画面のことですね。

こういったように何かと何かを結びつけるもの、これがインターフェースなのです。

じゃあ、プログラミングでいうところのインターフェースってどういうこと?
となりますが、これも利用側のクラス、使われる側のクラスの境界面がインターフェースになります。

インターフェースはクラスの境界面

※ちなみにこの図はUMLの記法に基づいています。

新人ちゃん
新人ちゃん

ふーん… つなぎ目ってことなんですね。
なんとなくはイメージできました

クラスとの違いは?

クラスとの違いが何なのか?というと、それはクラスの「継承」とインターフェースの「実装」の違いになります。

クラスの「継承」とは何か

元のクラスの中身を全部引き継いで、それに機能を足したり、既存の機能を変更したりすること。

クラスは元々中身が定義されていて状態変化や処理ができます。この中身を引き継いで新しいクラスを作るのが継承です。継承は元々あるものを取り込むイメージがあります。

インターフェースの「実装」とは何か

インターフェースというお約束に従って、それに見合うように中身を作っていくこと。

インターフェースそのものは空っぽで、入れ物があるだけです。
こんな使い方をしたらこういう形式の結果を返しましょう、こういう処理をしましょう、というお約束が書いてあるだけなのです。インターフェースの実装は、ボタン・レバー・ハンドル、といった操作をする取っ手を出して、その内側を作りこむイメージがあります。

お約束:正確には「仕様」と言います
中身を作る:これを「実装」と言います

インターフェースの使いどころ

個別のアプリを作るときにインターフェースを作ることはまずなくて、何らかのフレームワークを使っている際にインターフェースを実装する、というケースがほとんどだと思います。

じゃあなぜフレームワークはインターフェースを提示するのか?
実装が決められないのはどういう状況か、見ていきましょう!

ログイン処理(認証処理)

先に実装を決められないもの、それは例えばログイン機能です。

ログイン機能は細かいことを言うと

  • 認証:誰がアクセスしているのかを特定すること
  • 認可:特定されたユーザーに権限を与えること

に分かれますが、ここでは「認証」について扱います。

最近は認証パターンが多くて、ログイン先のサーバーで認証用の情報(ユーザーID、パスワード)をDBに持っているパターンのほか、GoogleやFacebookといった別の認証サービスを利用するなど様々です。

今後つくられるアプリケーションにどんな認証が使われるかはフレームワークを作る側にはわかりません。
このような場合に認証用のインターフェースだけを先に決めてしまうのです。たとえば:

// 認証インターフェース
interface Authenticator {
  boolean authenticate(String userId, String password);
}

のようなものを作っておけば、フレームワーク側はこれの実装クラスを使えばいいんですね。

もしDBで認証するなら:

// DBを使った認証処理
class DBAuthenticator implements Authenticator {
  boolean authenticate(String userId, String password) {
    // userIDを使い、DBからユーザー情報を取り出し、
    // そこにあるパスワードとpasswordを照合する。
  }
}

とか、もしGoogleを使うなら:

class GoogleAuthenticator implements Authenticator {
  boolean authenticate(String userId, String password) {
    // Googleの認証サービスを使った実装をする
  }
}

のように、アプリケーションごとに実装して、フレームワークに登録してあげればいいのです。

GUIのイベント処理

ほかの例としては、GUI(ウインドウが出てくるアプリケーション)を作る場合にもインターフェースは使われます。

Javaに標準でついてくるGUIフレームワークのawtには「イベントリスナー」という考え方があります。

例えばボタンを考えましょう。

ボタンを押したら、何かが起きないといけませんよね?
でもその「何か」はフレームワークを作っているときには決められません。
アプリケーション固有の実装になります。

そこでインターフェースの出番です。

ボタンを押した、などの切っ掛けをイベントといいますが、Java標準のGUIフレームワークawtでは「イベントリスナー」というインターフェースでイベントを受け取ります。一例はこちら:

public interface ActionListener extends EventListener {
  void actionPerformed(ActionEvent ev);
}

こんなやつ。これの実装クラスをボタンに登録してあげればよく、ボタンが押されるとactionPerformed()が実行されます。

共通仕様の表現

上記のパターンは「決められない」ことを解決するためのインターフェースでしたが、共通仕様を表現する使われ方もあります。例えばJavaのコレクションクラスのArrayList、LinkedListはどちらもListインターフェースを実装しています。

メリットをご説明するためにListが実装されていなければどうなるか、見ていきましょう。

例えばリストクラスを使った合計、平均処理を行うユーティリティクラス(便利クラス)を作ることを考えます。
例としてこんな実装になるでしょう:

public class StatUtil {
  static int sum(ArrayList list) {
    int s = 0;
    for(int value : list) {
      s += score[i];
    }
    return s;
  }
  static int sum(LinkedList list) {
    int s = 0;
    for(int value : list) {
      s += score[i];
    }
    return s;
  }
  static double average(ArrayList list) {
    return sum(list) / list.size();
  }
  static double average(LinkedList list) {
    return sum(list) / list.size();
  }
}

このクラスではsumメソッドが2回、averageメソッドが2回出てますが、
それはArrayListとLinkedListが異なるクラスだからです。
メソッドの中身は同じなのにクラスが異なるだけで複数実装しなければならないのは面倒ですね。

これが、ArrayList、LinkedListともListを実装していればどうでしょう。
こんな実装で済みます:

public class StatUtil {
  int sum(List list) { // ←引数の型に注目!
    int s = 0;
    for(int value : list) {
      s += score[i];
    }
    return s;
  }
  double average(List list) { // ←引数の型に注目!
    return sum(list) / list.size();
  }
}

コード量が半分で済みます!
しかも、今後Listインターフェースを実装するクラスがあれば、このコードを再利用できます。何も変更せずに!

まとめ

インターフェースのイメージ、付きましたでしょうか?

インターフェースは

  • クラスとクラスの境界面
  • 仕様を表現する

ものであり、メリットは

  • 実現方法決められないものについても仕様を決めて実装を後回しにできる
  • 仕様を共通化することで少ない実装量で多くの事柄に対応できる

ということでした。

新人君
新人君

あのー先生、インターフェースは「多重継承」できると聞いたのですが、
そのメリットはなんですか?

あっはっは…(^^;)
いい質問ですねぇ!

ちょっと今回は長くなってしまったので、それはまた別の機会に!

※多重継承の解説記事追加しました。記事はこちら

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です