株式会社イーヴ

EeBlog(テクニカルブログ)

TOP > EeBlog > 第24回 Guiceその2

第24回 Guiceその2

前回に引き続き、今回もDIフレームワーク「Guice」を学びます。

まずは前回のソースを見て、基本的なDIの流れを思い出しましょう。 最初はSportsインターフェースと、その具象クラスのBadmintonクラスからです。 Badmintonクラスはnew演算子が使えないようにコンストラクタをprivateにしてあります。

public interface Sports {
     void play();
 }

public class Badminton implements Sports {
    private Badminton() {
    }

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

GuiceではModuleインターフェースを実装することでインターフェースと具象クラスの関連付けを行います。
SportsModuleクラスでは、configureメソッドでSportsインターフェースとBadmintonクラスを結びつけています。

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

PlayerクラスにはSports型のフィールドがあります。
Injectアノテーションにより、依存性注入の対象として指定しています。
また、Badmintonクラスと同様にコンストラクタはprivateです。

import com.google.inject.Inject;

public class Player {
    @Inject
    private Sports sports;

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

        sports.play();

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

Mainクラスで依存性注入を行っています。
SportsModuleオブジェクトを使ってInjectorオブジェクトを作成し、そのInjectorオブジェクトによって、BadmintonオブジェクトがSports型のフィールドに注入された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();
    }
 }

以上がGuiceにおける基本的なDIの流れです。

 

今回はモックオブジェクトの作成やスコープの設定を行ってみましょう。 Singletonアノテーションを使うことで、MockSportsクラスはシングルトンとなります。

import com.google.inject.Singleton;

@Singleton
public class MockSports implements Sports {
    private MockSports() {

    }

    @Override
    public void play() {
        System.out.println("開発途中です。");
    }
 }

下記のように、バインド時にシングルトンを設定することもできます。

import com.google.inject.AbstractModule;
import com.google.inject.Scopes;

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

インターフェースにはImplementedByアノテーションを設定することで、デフォルトの実装を指定できます。

import com.google.inject.ImplementedBy;

@ImplementedBy(MockSports.class)
public interface Sports {
    void play();
 }

Moduleを指定せずにInjectorを生成した場合、ImplementedByアノテーションで指定されたMockSportsクラスが注入されるようになります。

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

public class Main {
    public static void main(String[] args) {
        Injector defaultInjector = Guice.createInjector();
        Player defaultPlayer = defaultInjector.getInstance(Player.class);
        defaultPlayer.play();

        Injector badmintonInjector = Guice.createInjector(new SportsModule());
        Player badmintonPlayer = badmintonInjector.getInstance(Player.class);  
        badmintonPlayer.play();
    }
 }

Guiceにはこの他にも多くのアノテーションがあり、より容易に開発を進められます。 また、GuiceをWebアプリケーションのフィルターとして使うことも可能で、ビジネスクラスをサーブレットに依存させないことにより、独立性が高められます。 他フレームワークと連携する機能もあり、struts2用のプラグインがあったり、Springと連携することができます。 興味をもたれた方は是非自分で調べてみてください。

 

以上、2回にわたってGuiceを学びました。 Guiceを通して、DIとはどういうことをするのか、アノテーションではどんなことができるのかを感じとっていただけたらと思います。 有用な考え方、有用な機能を自然に使えるエンジニアを目指しましょう。