読者です 読者をやめる 読者になる 読者になる

ほげほげ(仮)

仮死状態

Daggerを触ってみた

Android Java

気になっていたDaggerを少し触ってサンプルを作りました。公式のサンプルがぼくにとって分かりにくかったのですごくシンプルにしました。まだ分かってないこと多いです…

DaggerはAndroidJava向けの高速なDIコンテナです。
Daggerについて詳しくは公式をどうぞ。 http://square.github.io/dagger/

今回はシンプルにAndroidではなく普通のJavaとして使用しています。

簡単なサンプル

注入するinterfaceと実装クラス

interfaceを定義します。

public interface Sample {
    void execute();
}

注入する実装クラスを作っておきます。

public class SampleImpl implements Sample {

    @Override
    public void execute() {
        System.out.println("SampleImpl#execute");
    }

}

ここは普通のinterfaceとクラスです。特別なことは何もしてません。

利用する側のクラス

さきほどSampleを使用する側のクラスです。

import dagger.ObjectGraph;
import javax.inject.Inject;

public class DemoObject {
    @Inject Sample sample;

    public DemoObject() {
        // 注入
        ObjectGraph objectGraph = ObjectGraph.create(new SampleModule());
        objectGraph.inject(this);
    }

    public void run() {
        sample.execute();
    }
}

ここのコンストラクタでフィールドのSampleインターフェイスに実装クラスを注入しています。

ObjectGraphは依存を解決するためのクラスになります。これを使用してフィールドへ注入を行います。

注入対象のフィールドには@Injectアノテーションを付与しておく必要があります。

この時点SampleModuleは作ってないのでコンパイルエラーになります。この次に作ります。

モジュールの定義

依存を注入するための定義を行うクラスです。

import dagger.Module;
import dagger.Provides;

@Module(injects = DemoObject.class)
public class SampleModule {
    @Provides
    Sample provideSample() {
        return new SampleImpl();
    }
}

まず@Moduleアノテーションで注入対象クラスをinjectsで指定しています。これがないと正しく動作してくれません。

@Providesアノテーションをつけたメソッドでどのインスタンスを注入するかを定義します。注入したいインスタンスを返却します。

一般的にこのクラスはModuleサフィックスをつけ、@Providesメソッドにはprovideプレフィックスをつけるみたいです。

テスト用の実行クラス

これを動かすためのMainクラスを作っておきます。

これを実行すると動くと思います。

public class Main {
    public static void main(String[] args) {
        DemoObject demoObject = new DemoObject();
        demoObject.run();
    }
}

なんかメモ

シングルトンのインスタンスを作りたい

モジュールクラスの@Providesメソッドに追加で@Singletonをつければよいです。

import dagger.Module;
import dagger.Provides;

@Module(injects = DemoObject.class)
public class SampleModule {
    @Provides @Singleton
    Sample provideSample() {
        return new SampleImpl();
    }
}

使っていない@Providesがある

Daggerはコンパイル時に検証を行い、何かおかしなところがエラーになります。

ライブラリかなんか作る時だとは思いますが、@Providesメソッドが定義されているが使われていない場合にエラーになります。

Graph validation failed: You have these unused @Provider methods

これを回避するには@Moduleに追加で指定が必要です。

@Module(
    injects = DemoObject.class,
    library = true
)

実装クラスのコンストラクタに引数渡したい

  • 実装クラス
import javax.inject.Inject;

public class SampleImpl implements Sample {

    private final String value;

    @Inject
    public SampleImpl(String value) {
        this.value = value;
    }

    @Override
    public void execute() {
        System.out.println(value);
    }
}
  • モジュール定義
import dagger.Module;
import dagger.Provides;

@Module(
    injects = DemoObject.class
)
public class SampleModule {

    private final String value;

    public SampleModule(String value) {
        this.value = value;
    }

    @Provides
    Sample provideSample() {
        return new SampleImpl(value);
    }

}
  • ObjectGraph生成
ObjectGraph objectGraph = ObjectGraph.create(new SampleModule("hoge"));

実装クラスにコンストラクタを渡す時はモジュールのコンストラクタで引数を渡してフィールドに保持し、@Providesメソッドでインスタンスを生成するときにさっきのフィールドから引数に渡す感じで出来ました。

これが正しいかは謎ですが。

公式ドキュメントで分からないところ

公式ドキュメントの最初の方にでてくる

@Provides Pump providePump(Thermosiphon pump) {
  return pump;
}

の箇所がよく分からない…

他にもまだ見てないところあるけど、最初からつまづいた。

まとめ

自分なりに理解するために色々試しながら簡単なサンプルを作ったおかげで少し理解できた気がします。

最初は公式ドキュメントとGitHubのソースを見ながらやったんですが、ドキュメントはところどころが端折ってサンプルソースは途中経過が分からなくて…ぼくは残念ながら簡単に理解できなかったです。

RoboGuiceくらいしかDIは使ったことがなかったですが、軽量で高速なので使用を検討してみたいと思います。

次はAndroidでのサンプルを作ってみようかな。

参考