【Java】「インターフェース」って何のためにあるの?魔法の共通規格をマスターしよう!
はじめに
みなさんどうも、おげんです。
前回は、相手が誰でも同じ命令で動かせる「ポリモーフィズム」についてお話ししました。 「親の型でまとめて扱う」という技を知ると、コードが一気にプロっぽくなってワクワクしますよね。
でも、学習を進めているとこんな疑問が浮かんできませんか?
「『人間』と『ドローン』みたいに、種類(クラス)が全然違うもの同士に、同じ動きをさせたい時はどうすればいいの?」
継承は「親子関係」なので、全く違う種類のものを無理やり一つにまとめることはできません。 そこで登場するのが、「インターフェース(interface)」です!
今回は、オブジェクト指向をさらに柔軟にしてくれる「インターフェース」という魔法の道具について、分かりやすく解説していきます。
- 「継承」と「インターフェース」の違いがイマイチ分かっていない人
- 「インターフェースって結局、何のためにあるの?」と疑問に思っている人
- 4月の実務に向けて、大規模な開発でも通用する「設計の基本」を知りたい人
- 「 implements 」という単語を見て、難しそう…と身構えてしまう人
インターフェースは「能力の証明書」
前回学んだ「継承」は、いわば「血のつながり(親子)」でした。
「戦士はキャラクターの一種である」という、種類そのものを引き継ぐイメージです。
対してインターフェースは、「資格や免許(ライセンス)」のようなものです。
「血縁」と「資格」の違いって?
RPGで例えると、こんな違いがあります。
- 継承: キャラクターの子として「戦士」や「魔法使い」が生まれる。
- インターフェース: 種類に関係なく、特定の特訓をしたものだけが「空を飛べる(Flyable)」という免許をもらう。
例えば、「魔法使い」と「ドローン」は、クラスとしては全くの別物ですよね。
でも、どちらも「空を飛ぶ」という動きは共通しています。
「種類が違うから継承はできないけど、同じ能力(メソッド)を持っていることだけは保証したい!」
そんな時に「空飛ぶ免許(インターフェース)」を渡すことで、全く別の種類のもの同士でも同じように扱えるようになるんです。
ルールを決めるのが仕事
インターフェースの最大の特徴は、「『何をするか』だけを決めて、『どうやるか』は書かない」という点です。
「空を飛ぶ免許(Flyable)」には、「fly() というメソッドを持ってなきゃダメだよ!」というルールだけが書いてあります。
実際にほうきで飛ぶのか、プロペラで飛ぶのかは、免許を受け取った側が自由に決めていいんです。
Javaでの書き方:interface と implements
インターフェースを使うときは、専用の「インターフェース定義」を作り、それを使うクラスで「実装」という作業をします。
① インターフェース(免許)を作る
まずは「空を飛ぶ能力」という免許を定義します。Javaでは class ではなく interface と書くのがポイントです。
// インターフェース:能力の名前だけ決める
interface Flyable {
void fly(); // 中身( { } )は書かない!
}② クラスで「免許」を取得する
次に、この免許を使いたいクラスで implements(実装する)というキーワードを使います。
// 魔法使いクラスが「空飛ぶ免許」を取得
public class Wizard extends Character implements Flyable {
// 免許のルールに従って、具体的な飛び方を書く(必須!)
@Override
public void fly() {
System.out.println(name + "は魔法のほうきで空を舞った!");
}
}- implements(実装): 「この免許のルールをちゃんと守ります!」という宣言です。
- 強制力がある:
implementsしたのにfly()メソッドを書かないと、Javaが「免許持ってるのに飛び方を知らないのはダメだよ!」とエラーを出して教えてくれます。
これで、「継承(extends)」で親子の絆を持ちつつ、「インターフェース(implements)」で新しいスキルを習得するという、ハイブリッドなクラスが完成しました!
なぜインターフェースを使うのか?(実務の視点)
「わざわざインターフェースを作らなくても、普通にクラスにメソッドを書けばいいじゃん」と思うかもしれません。
でも、インターフェースを使うと「ポリモーフィズムがさらにパワーアップ」するんです!
種類が違っても「同じ能力」でまとめられる
例えば、ゲームの中に「魔法使い(人間)」と「ドローン(機械)」が登場するとします。
この2つは全く別物なので、同じ親クラス(Character)を持つのは不自然ですよね。
でも、どちらも「空を飛ぶ」という共通点があれば、Flyable型として一つのリストにまとめられます。
// 全く別の種類のものを、同じ「免許」の型でまとめる!
List<Flyable> flyingObjects = new ArrayList<>();
flyingObjects.add(new Wizard()); // 魔法使い
flyingObjects.add(new Drone()); // ドローン
// まとめて「飛べ!」と指示が出せる
for (Flyable f : flyingObjects) {
f.fly(); // 相手が誰でも「飛べること」は保証されているから安心!
}「中身」が決まってなくても「計画」が立てられる
実務では、チームで分担して作業します。
「飛び方の詳細は後でドローン担当の人が決めるけど、とりあえず『飛ぶ(fly)』というボタンだけは先に作っておきたい」という時、インターフェースがあれば解決です。
「中身は空っぽでも、名前とルールだけ決めて共有できる」
これが、大規模な開発でインターフェースが重宝される最大の理由です。
まとめ:インターフェースは設計のカナメ
今回は、クラスに特定の能力を授ける「インターフェース」についてお話ししました。
「継承」と似ていて混乱しやすいですが、使い分けのポイントはたった一つです。
- 継承(extends): 「血縁関係」。そのものズバリの種類を引き継ぐ(例:戦士はキャラクターだ)。
- インターフェース(implements): 「免許・資格」。種類は違っても、できることを共通化する(例:魔法使いもドローンも飛べる)。
ポイントを振り返ると:
- インターフェース: メソッドの名前(ルール)だけを決めて、中身は書かない。
- implements: インターフェースを実装すること。「ルールを必ず守ります」という誓い。
- メリット: 全く違う種類のクラスを同じ型として扱えるので、プログラムの柔軟性が爆上がりする!
最初は「わざわざ型を分けるなんて面倒だな」と感じるかもしれません。
でも、実務で巨大なシステムを作るようになると、この「インターフェースでルールだけ先に決めておく」という手法が、バグを防ぎ、開発スピードを上げるための最強の手段になります。
これでオブジェクト指向の基本の「き」はマスターです! 自信を持って、実務に飛び込んでいきましょう!
今回も最後まで読んでいただき、ありがとうございました!
