Java初心者必見!インタフェースと依存性注入をかんたん解説

こんにちは。ゆうせいです。

今回は、Javaの学習を始めたばかりの新人エンジニアに向けて、「インタフェース」と「依存性注入(Dependency Injection)」という2つの重要な概念をやさしく解説していきます。

いきなりカタカナが多くて少し構えてしまうかもしれませんが、大丈夫です。例え話をまじえながら、実践的な理解につながるように丁寧に説明します!


インタフェースとは?~契約書のようなもの~

インタフェースの基本的な考え方

Javaにおける「インタフェース(interface)」は、一言で言えば「メソッドの仕様だけを定めた設計図」です。

もう少しかみ砕くと、「このクラスはこういう機能を持っているよ!」と約束(契約)するための仕組みなんです。

たとえば、「プリンタ」というクラスを作る場合、「印刷する(print)」という機能を持っているとしましょう。これをインタフェースで定義すると以下のようになります。

public interface Printer {
    void print(String message);
}

このインタフェースを「契約書」だと考えてください。この契約書にサインしたクラスは、必ずprint()というメソッドを実装しなければなりません。

インタフェースの実装例

public class InkjetPrinter implements Printer {
    public void print(String message) {
        System.out.println("インクジェット印刷: " + message);
    }
}

public class LaserPrinter implements Printer {
    public void print(String message) {
        System.out.println("レーザー印刷: " + message);
    }
}


このように、インタフェースによって「使い方を統一」しながら、中身の処理はクラスごとに自由にできます。

依存性注入とは?~電池を取り替えられる懐中電灯のようなもの~

依存性とは?

「依存性」とは、あるクラスが別のクラスに頼っている関係のことです。

たとえば、DocumentPrinterというクラスがあって、Printerに依存している場合:

public class DocumentPrinter {
    private Printer printer;

    public DocumentPrinter() {
        this.printer = new InkjetPrinter(); // ここで依存してしまっている!
    }

    public void printDocument(String text) {
        printer.print(text);
    }
}

このようにコードの中でnewしてしまうと、他のPrinterに切り替えたくなったときに修正が大変です。

依存性注入(Dependency Injection, 略してDI)とは?

依存するオブジェクトを外から渡す(注入する)ことで、コードの柔軟性を高める手法が「依存性注入」です。

public class DocumentPrinter {
    private Printer printer;

    // 依存性を注入するコンストラクタ
    public DocumentPrinter(Printer printer) {
        this.printer = printer;
    }

    public void printDocument(String text) {
        printer.print(text);
    }
}

これでDocumentPrinterは、InkjetPrinterでもLaserPrinterでも、どんなPrinterでも対応できるようになります。

図で理解しよう!

+------------------+         +--------------------+
|  DocumentPrinter | ----->  |   Printer (interface) |
+------------------+         +--------------------+
                                      ^
                                      |
                    +----------------+----------------+
                    |                                 |
          +-------------------+         +---------------------+
          |  InkjetPrinter    |         |   LaserPrinter      |
          +-------------------+         +---------------------+

このように、DocumentPrinterはどのプリンタにも依存できる、拡張性の高い設計になっています。


なぜインタフェースとDIが大事なのか?

メリット

メリット内容
柔軟性仕様を変えずに中身の実装を変更できる
テストしやすいテスト用のダミー(モック)を注入できる
拡張しやすい新しい機能を追加しても既存コードに影響が少ない

デメリット(注意点)

デメリット内容
学習コスト最初は仕組みが少し難しいと感じることも
実装が冗長小さいプロジェクトではオーバースペックになりやすい

例え話でイメージしよう!

プリンタを家電製品、DocumentPrinterをそれを操作する人と考えてみましょう。

  • インタフェース: 「電源ボタン」や「印刷ボタン」はどのメーカーも共通。
  • 実装クラス: メーカー(CanonやEpson)によって、出力の質や速さは違う。
  • 依存性注入: あなたの部屋にあるプリンタを「差し替え可能」にする仕組み。

つまり、操作方法は変わらないけど、中身は自由に変えられる。 これが設計として非常に重要なんです!


よくある質問

Q. インタフェースと抽象クラスってどう違うの?

A. 抽象クラス(abstract class)は共通のコード(実装)を持てる点がインタフェースと違います。インタフェースは仕様だけ定義して、実装は一切持ちません。

Q. 依存性注入はどうやって実現するの?

A. 手動でコンストラクタに渡す方法(今回紹介したもの)もあれば、Springなどのフレームワークを使う方法もあります。


今後の学習の指針

次のステップとしては、以下の内容を学んでみましょう!

  • Javaの抽象クラスとインタフェースの比較
  • Spring Frameworkにおける依存性注入(DIコンテナ)
  • テスト駆動開発(TDD)とモックの使い方
  • SOLID原則(特に「依存性逆転の原則」)

ゆっくりで大丈夫です。まずは、「インタフェースは契約、DIは部品の差し替え」とイメージできれば上出来です!

何か分からないところがあったら、気軽に聞いてくださいね。


セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。