気になる開発プロダクツ

第1回[後編] Guice 1.0 - GoogleからリリースされたDIフレームワーク

この記事を読むのに必要な時間:およそ 3 分

前編では,Guiceの概要と導入,そしてGuiceによるDIの設定からインスタンスの生成と実行までの一連の流れについて解説しました。後編ではDIの設定における応用テクニックについて解説します。

応用編

応用編では,DIの設定について3つの方法を紹介します。そして最後にサーブレット(Webアプリケーション)で利用する方法を紹介します。

DIの設定

方法その1-依存性をアノテーションで指定する

GuiceによるDIの設定は,前編で紹介したもの以外にもいくつかの方法が用意されています。ここでは,注入する具象クラスをアノテーションで指定する方法を紹介します。これにより,ソースコードの記述をよりシンプルにすることができます。

具体的には,インターフェースに対応する注入される具象クラスを,アノテーション@ImplementedByで指定します(リスト5)。これでモジュールの作成が不要になると共に,Injectorを生成するcreateInjector()メソッドの引数も不要になります。

リスト5 インターフェースに対応するされる具象クラス(依存性)をアノテーションで指定

  // インターフェースPlayにPlayImplを対応させる
  // (注入する依存性の設定)
  @ImplementedBy( PlayImpl.class )
  public interface Play  {
    void play();
  }
方法その2-注入の対象に名前をつける

依存性を注入する対象が複数存在するときには,それぞれに名前がつけてあると便利です。名前はアノテーション@Namedでリスト6のようにつけます。ここではプリミティブ型(int)の変数に名前をつけていますが,一般のオブジェクトであっても同じです。

リスト6 注入の対象に@Namedで名前をつけた

  class Exam  {
    @Inject public Exam()  {}
    @Inject @Named("perfect") int perfect;  // 満点
    @Inject @Named("high")    int high;     // 高得点
    @Inject @Named("passing") int passing;  // 合格点
  }

@Namedによって名前をつけられた対象に依存性を注入する場合は,リスト7のようにannotatedWith()とnamed()の両メソッドを使います。named()はcom.google.inject.name.Namesクラスのメソッドですが,このクラスの静的(static)インポートによって,メソッド名だけの記述にしています。

リスト7 名前をつけられた対象に定数を設定

  Injector injector = Guice.createInjector( new AbstractModule() {
    protected void configure()  {
      bind( int.class ).annotatedWith( named( "perfect" ) ).toInstance( 100 );
      bind( int.class ).annotatedWith( named( "high"    ) ).toInstance(  80 );
      bind( int.class ).annotatedWith( named( "passing" ) ).toInstance(  60 );
    }
  });
  Exam exam = injector.getInstance( Exam.class );
方法その3 - Providerによるインスタンスの生成

先ほどまでの例では,new演算子でインスタンスを生成するのとあまり変わりがないと思うかもしれません。しかしGuiceでは,インスタンスの生成時により複雑な処理を行うこともできます。それを担うのがProviderです。

たとえば通販サイトを想定して,注文明細データを持つCartインスタンスを内包したOrderインスタンスを生成するとします。このとき,Injectorを使ってこのインスタンスを生成するにはどうしたらよいでしょうか。ただしOrderとCartは同じインターフェースを持っていないとします。こうしたときProviderを使うのが有効です。

先にInjectorとモジュールを見てみましょう(リスト8)。toProvider()メソッドと,OrderProviderクラスが新たに現れました。このクラスはすぐあとで作成しますが,Orderインスタンスを生成する処理が記述されています。

リスト8 Provider(OrderProvider)が用いられるInjectorの生成

  Injector injector = Guice.createInjector( new AbstractModule() {
    protected void configure()  {
      bind( Order.class ).toProvider( new OrderProvider( 1 ) );
    }
  });

OrderProviderクラスはリスト9のように作成しました。インスタンスの生成はget()メソッドで行われます。このメソッドの戻り値の型とProvider<Order>における<Order>の部分とが同じでなければなりません。この部分は<T>のようにテンプレート型で表すこともできます。その場合はget()メソッドの戻り値もT型として宣言します。

リスト9ではCartのコンストラクタに付与されたIDが引数で渡されますが,このIDはInjectorによりOrderインスタンスが生成されるたびに1ずつ増えるようになっています。つまり注文が入るたびに付与されるIDが増えていくということになります。本来の業務アプリケーションであれば,IDはデータベースなどで生成されたものを使うことになるでしょう。

リスト9 Orderインスタンスを生成するProviderクラス(OrderProvider)

  class OrderProvider implements Provider<Order>  {
    int id = 0;
    public OrderProvider( int id )  {  this.id = id;  }
    public Order get()  {
      // CartインスタンスにIDを付与している
      return  new Order( new Cart( id++ ) );
    }
  }

著者プロフィール

沖林正紀(おきばやしまさのり)

SE/プログラマを経て,WebアプリケーションやXMLなどについて雑誌記事や書籍の執筆活動を始める。大手メーカで製品資料の作成や,セミナーの講師を担当したこともある。現在は,取材記事や製品レビューなどに執筆活動の幅を広げる一方,プログラミング教材の開発も手がけている。

著書

コメント

コメントの記入