インタフェースを理解する

インタフェースと言えば、ユーザインターフェース(画面)という使い方の意味でなじみがあると思いますが、Javaのインタフェースは画面のことではありません。インタフェースとは、

    • どのような変数やメソッドを持つのかを定義しただけのクラス
    • 変数は定数宣言のみ
    • メソッドは抽象メソッド(宣言だけで内部処理は書かない)

ということです。メソッドというのはある意味、クラスの入出力インタフェースの位置づけになりますから、あながち一般的なインタフェースという意味と似ているかもしれません。

インタフェースクラスの記述と利用方法

interface PCmouse {

void rightClick();

void leftClick();

void wheel();

}

class MouseSoft implements PCmouse{

public void rightClick() {

System.out.println("あとに戻る");

}

public void leftClick() {

System.out.println("次にすすむ");

}

public void wheel() {

System.out.println("スクロールする");

}

}

public class intermain {

public static void main(String[] args) {

MouseSoft ms = new MouseSoft();

ms.leftClick();

ms.rightClick();

ms.wheel();

}

}

クラスにインタフェースを実装する場合には、そのインタフェースで宣言されているメソッドはすべて実装しなければなりません。そうしないと、コンパイル時にエラーが発生します。

UMLによるインタフェースの記述

インタフェースクラスを用意する意義

大雑把にいうと、以下の2つの意義があるといえます。

    1. クラスを作成する際に、どのようなメソッドが必要になるのかが明示的になる
    2. ポリモーフィズムをより柔軟に実現できる。

前者については、コンパイル時にエラーでることからわかるようにメソッドの実装を強制しますので、プログラムの信頼性が高まるといえます。

後 者については、近年はインターフェースを利用したポリモーフィズムの実現が注目を浴びています。継承のページでも説明したように、継承を利用すれば、継承 しているスーパークラスと同様に扱うことができます。インタフェースでも同様な処理を行うことができます。つまり、同じインタフェースを実装 (implement)したクラスは、そのインタフェースとして同様に扱うことができます。ここで、継承とインタフェースを比較して説明します。

    • 継承 ・・・ 家系的なクラスのグループ化
    • インタフェース ・・・ 継承関係を超えたクラスのグループ化

昨今のオブジェクト指向設計モデルでは、インタフェースを介してクラスを利用するアプローチが注目を浴びています。

以 上の話を「車」をたとえに説明しましょう。現在、日本には大手の自動車メーカーが数社存在してますが、それぞれのメーカーは、独自の車をデザインして、○ 代目カローラとか、○代目スカイラインとか、○代目RX-7.... など進化しています。ある意味、それらの車の特徴は時代が変わっても継承されているといえます。しかし、ある車を乗り続けたユーザが他車に乗り換えたとし ても、問題なく車を運転することはできると思います。なぜでしょうか?それは、「車」という共通したインターフェースを持っているからです。たとえば、車 にはアクセルやブレーキ、ハンドルなど共通したものがあります。それぞれの血筋が違っていても、インタフェースが同じなので「車」として操作することがで きるのです。

継承とインタフェースの違いを車の話で説明すれば、

    • 継承関係に着目したクラスの利用 ・・・ 同じ系列のクラスのみ同一に扱える
    • インタフェースに着目してクラスの利用 ・・・ 車のインタフェースを持っていれば、どんなクラスでも同一に扱います

ということです。後者のほうが依存性が低くなりますね。

インタフェース介したクラスの利用サンプルと演習

以下のソースを入力し、UML図を書いて各クラスの関係を理解しなさい。

intersample.java

interface Racer{

void accel();

}

abstract class FAIRLADY {

String engine;

abstract void Engine();

FAIRLADY(){

maker();

Engine();

}

void maker(){

System.out.println("日産です");

}

public void accel(){

System.out.println(this.engine+" 全開だぜ!");

}

}

class S30 extends FAIRLADY{

void Engine(){

this.engine="直列6気筒のL型エンジン";

}

}

class Z33 extends FAIRLADY implements Racer{

void Engine(){

this.engine= "V6エンジン";

}

}

abstract class SKYLINE {

String engine;

String name;

abstract void Engine();

abstract void Name();

SKYLINE(){

Name();

System.out.println("私の名前は"+ this.name);

Engine();

Taillamp();

}

void Taillamp(){

System.out.println("丸いランプが特徴です");

}

public void accel(){

System.out.println(this.engine+" バリバリだぜ");

}

}

class GTR extends SKYLINE implements Racer{

void Name(){

this.name="GTR";

}

void Engine(){

this.engine="ターボエンジン搭載";

}

}

class V35 extends SKYLINE{

void Name(){

this.name="V35";

}

public void Engine(){

this.engine="VQ30DD型エンジン";

}

void Taillamp(){

System.out.println("丸いランプが廃止されました");

}

}

public class intersample {

public static void main(String[] args) {

FAIRLADY F;

SKYLINE S;

System.out.println("\n普通の使い方");

System.out.println("(FAIRLADYの場合)");

S30 s = new S30();

s.accel();

Z33 z = new Z33();

z.accel();

System.out.println("(SKYLINEの場合)");

GTR g = new GTR();

g.accel();

V35 v = new V35();

v.accel();

System.out.println("\nスーパークラスによるポリモーフィズムを利用した使い方");

System.out.println("(FAIRLADYの場合)");

F= new S30();

F.accel();

F= new Z33();

F.accel();

System.out.println("(SKYLINEの場合)");

S= new GTR();

S.accel();

S= new V35();

S.accel();

System.out.println("\nインタフェースによるポリモーフィズムを利用した使い方");

System.out.println("(SKYLINEの場合)");

Racer r = new GTR();

r.accel();

System.out.println("(FAIRLADYの場合)");

r = new Z33();

r.accel();

}

}