インタフェースを理解する
インタフェースと言えば、ユーザインターフェース(画面)という使い方の意味でなじみがあると思いますが、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つの意義があるといえます。
- クラスを作成する際に、どのようなメソッドが必要になるのかが明示的になる
- ポリモーフィズムをより柔軟に実現できる。
前者については、コンパイル時にエラーでることからわかるようにメソッドの実装を強制しますので、プログラムの信頼性が高まるといえます。
後 者については、近年はインターフェースを利用したポリモーフィズムの実現が注目を浴びています。継承のページでも説明したように、継承を利用すれば、継承 しているスーパークラスと同様に扱うことができます。インタフェースでも同様な処理を行うことができます。つまり、同じインタフェースを実装 (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();
}
}