株式会社イーヴ

EeBlog(テクニカルブログ)

TOP > EeBlog > 第23回 Guiceその1

第23回 Guiceその1

今回のテーマは「Guice」です。

まず「Guiceとは何ぞや」というところから始めます。 Guice(ジュースと読みます)はGoogleがオープンソースとして公開したDIフレームワークです。 SpringやSeasar2といった有名どころとの大きな違いは、依存性注入の設定をxmlファイルに記述するのではなく、Javaで記述するという点です。

Javaで依存性注入の設定をするということに、どういうメリットがあるのでしょうか。 実はxmlによる設定の場合、クラス名などの記述ミスがあっても、プログラムを実行してみないと間違いがわからないのです。 Javaでの設定の場合は、コンパイル時点でエラーが発生するので、実行前に記述ミスが明らかになります。 また、JUnitなどのテスティングフレームワークによる単体テストも容易になります。

それでは、簡単なプログラムを使って、GuiceによるDIを説明していきます。

public class Player {
     public void play() {
         System.out.println("ウォームアップします。");

         Badminton badminton = new Badminton();
         badminton.play();

	 System.out.println("クールダウンします。");
     }
 }
public class Badminton {
     public void play() {
         System.out.println("バドミントンして遊びます。");
     }
 }

BadmintonクラスがないとPlayerクラスはコンパイルさえできません。 依存関係の解決前の状態です。

 

では、Guiceを使用してコードを変更していきます。 まずSportsインターフェースを作成し、Badmintonクラスを変更します。

public interface Sports {
     void play();
 }
public class Badminton implements Sports {
     @Override
     public void play() {
         System.out.println("バドミントンして遊びます。");
     }
 }

次にSportsインターフェースとBadmintonクラスを結びつけるためのSportsModuleクラスを作成します。
GuiceではModuleインターフェースを実装することで依存性の注入の設定を行うのですが、直接Moduleインターフェースを実装するのではなく、AbstractModuleを継承することで、若干記述を減らすことができます。
configureメソッドでSportsインターフェースとBadmintonクラスを結びつけるための具体的な処理を行っています。
なお、bind(クラスA).to(クラスB)の場合において、クラスAとクラスBがis-a関係にないとコンパイルエラーが発生します。
これはジェネリクスの型変数によって実現されている処理です。

public class SportsModule extends AbstractModule {
     @Override
     protected void configure() {
         bind(Sports.class).to(Badminton.class);
     }
 }

PlayerクラスにはSports型のフィールドを持たせて、Injectアノテーションを記述します。
これにより、Sports型のフィールドに依存性が注入されます。
Injectアノテーションはフィールドに限らず、コンストラクタや任意のメソッドに指定できます。
また、アクセス修飾子がprivateであっても関係ありません。

import com.google.inject.Inject;

public class Player {
    @Inject
    private Sports sports;

    public void play() {
        System.out.println("ウォームアップします。");

        sports.play();

        System.out.println("クールダウンします。");
     }
 }

最後にPlayerクラスを実行するクラスを作成します。
ここで先ほどのSportsModuleクラスを使用して、注入を実行するInjectorを作成します。
作成されたInjectorによって、Playerクラスのインスタンスが依存性注入された状態で生成されます。

import com.google.inject.Guice; 
import com.google.inject.Injector;

public class Main {     
    public static void main(String[] args) {         
        Injector injector = Guice.createInjector(new SportsModule());

        Player player = injector.getInstance(Player.class);         
        player.play();     
    }
}

以上の構成により、PlayerクラスとBadmintonクラスの依存関係が解消されました。

 

ちなみに、new演算子でPlayerクラスのインスタンスを生成した場合、playメソッドを実行したら確実にNullPointerExceptionが発生します。 プログラマにnew演算子を使わせないためには、コンストラクタをprivateにしましょう。

Guiceはコンストラクタがprivateなクラスでもインスタンス生成できますので、PlayerクラスとBadmintonクラスのコンストラクタを

privateにした場合でも、上記のコードは問題なく動作します。

次週も引き続きGuiceによるDIを学びます。