第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を学びます。

