【Java】「インターフェース」で多機能なクラスを作る!抽象クラスとの決定的な違い
はじめに
前回は、不完全な設計図である「抽象クラス(abstract)」について解説しました。
実は、Javaにはもう一つ、クラスに「ルール」を強制するための仕組みがあります。
それが「インターフェース」です。
「抽象クラスがあるなら、インターフェースなんていらないのではないか…」
「どちらも『実装を強制する』ものだよね?」
そう思う方も多いはずです。
しかし、この2つには「たった一つの、しかし決定的な違い」があります。
今回は、インターフェースの正体と、抽象クラスとの使い分けの極意を解き明かしていきます。
インターフェースは「後付けできる能力」である
抽象クラスが「乗り物」や「人間」といった「そのものの正体(性質)」を決めるものだとしたら、インターフェースは「できること(能力)」を定義するものです。
これをRPGのキャラクターで例えると、非常に分かりやすくなります。
- 抽象クラス(Character): 名前がある、HPがある、歩ける(キャラクターとしての基本)。
- インターフェース(Flyable): 「空を飛べる」という追加スキル。
- インターフェース(Swimmable): 「泳げる」という追加スキル。
「勇者」は人間ですが、修行をしたり魔法の靴を履いたりすれば、後から「空を飛ぶ」能力を手に入れることができますよね。
このように、クラスの正体が何であれ、特定の能力(メソッド)をセットできるのがインターフェースの最大の魅力です。
「何者であるか(Is-a)」ではなく、「何ができるか(Can-do)」。
この視点の切り替えが、インターフェースを使いこなす第一歩となります。
インターフェース最大の武器「多重実装」
Javaのクラス継承(extends)には、「親は一人しか選べない(単一継承)」という非常に厳しいルールがあります。
一人の人間が「犬」と「鳥」の両方の子供にはなれないのと同じです。
しかし、インターフェースを使えば、この制約を軽々と突破できます。
なぜなら、インターフェースは「正体」ではなく「能力(スキル)」だからです。
一人の人間が「水泳」と「料理」の両方のスキルを持っていても、何もおかしくはありませんよね。
これをプログラミング用語で 「多重実装(たじゅうじっそう)」 と呼びます。
// 能力1:空を飛べる
public interface Flyable {
void fly();
}
// 能力2:泳げる
public interface Swimmable {
void swim();
}
// 勇者は「人間」であり、かつ「空も飛べる」し「泳げる」!
public class Hero extends Human implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("マントを広げて空を飛ぶ!");
}
@Override
public void swim() {
System.out.println("力強くクロールで泳ぐ!");
}
}カンマ区切りでいくらでも追加できる
キーワードは implements(実装する) です。
クラス名の後ろに記述し、カンマで区切ることで、2つでも3つでも好きなだけ能力を追加できます。
「親は一人だが、身につけるスキルは無限大」。
この柔軟性こそが、複雑なプログラムを整理整頓しながら拡張していくための、インターフェース最大の武器なのです。
抽象クラスとインターフェース、どっちを使う?
「どちらもメソッドの実装を強制できるなら、どっちでもいいじゃないか…」と考えてしまいがちですが、プロの現場には明確な使い分けの基準があります。
迷ったときは、この「魔法の質問」を自分に投げかけてみてください。
判断基準1:「正体」か「能力」か
- 「AはBの一種である(Is-a関係)」なら、抽象クラス (例:勇者は「人間」の一種である →
abstract class Human) - 「AはBができる(Can-do関係)」なら、インターフェース (例:勇者は「空を飛ぶこと」ができる →
interface Flyable)
判断基準2:「共通の財産」があるか
- 名前やHPなど、共通の「変数(フィールド)」を持たせたいなら、抽象クラス (抽象クラスは状態を持てますが、インターフェースは基本的に「定数」しか持てません)
- 「やり方(メソッドの形)」だけを約束させたいなら、インターフェース
迷ったら「インターフェース」を優先する
現代のオブジェクト指向設計では、「継承(extends)よりも、インターフェースの実装(implements)を優先せよ」という格言があります。
継承は強力すぎて、一度使うとクラス同士の結びつきが強くなりすぎてしまい、後から修正するのが大変になるからです(これを「密結合」と呼びます)。
一方で、インターフェースは「後付けのスキル」なので、必要なくなれば外すのも、別のスキルに入れ替えるのも簡単です。
「どうしても共通の変数を持ちたい!」という時以外は、まずはインターフェースで設計できないか考えてみるのが、スマートなプログラマーへの近道ですよ。
まとめ:インターフェースで「自由自在な設計」を手に入れよう
今回は、クラスに新しい可能性を付け足す 「インターフェース(interface)」 について解説しました。
最後に、設計の迷いをなくすためのポイントを振り返ります。
- インターフェースは「能力」: クラスの正体に関係なく、「~ができる」というスキルを定義する。
- 多重実装(implements)が最強:
extendsと違い、カンマ区切りでいくらでも能力を追加できる。 - 使い分けの極意: 「何者か」は抽象クラスで、「何ができるか」はインターフェースで。
「組み合わせる」という考え方
これまでの記事で学んだ「継承」は、親の財産をすべて受け継ぐ強力な武器でした。
しかし、インターフェースを学んだ今のあなたなら、もう一つの選択肢を持っています。
それは、「必要な能力だけをパズルのように組み合わせて、クラスを作る」 という考え方です。
「何でもできる巨大な親クラス」を作るのではなく、「空飛ぶ機能」「泳ぐ機能」と小さく分けて管理する。
そうすることで、プログラムの一部を変更しても全体が壊れにくい、プロレベルの「柔軟な設計」ができるようになります。
Javaのオブジェクト指向、その深い森をここまで一緒に歩いてきてくれてありがとうございました。
