Dagger2とは
依存性注入フレームワークのこと。
内容
自身の理解のために、公式ページの以下の内容を荒く訳してます。
https://dagger.dev/users-guide.html
- Declaring Dependencies
- Satisfying Dependencies
- Building the Graph
@Inject
アノテーションについて
Daggerがクラスのインスタンスを作成するために使用するコンストラクタに@Inject
アノテーションを付与する。新しいインスタンスが要求される際に、Daggerは要求されたパラメータを取得し、このコンストラクタを呼ぶ。
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
...
}
Daggerは@Inject
が付いたフィールド変数に直接注入する。
この例では、フィールド変数のheater、pumpにHeaterインスタンスとPumpインスタンスを注入する。
class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;
...
}
@Provides
、@Module
について
デフォルトでは、Daggerは要求された型のインスタンスを構築することで各依存関係を満たす。
しかし、@Inject
はどこでも使えるわけでない。
- インタフェースは構築できない
- サードパーティのクラスはアノテーションを付与できない
- 設定可能(Configurable)なオブジェクトは設定していなくてはいけない
これらのケースでは@Provides
アノテーションを付与されたメソッドを使う。
返り値の型は依存関係を満たすものを定義する。
例えば、provideHeater()はHeaterが要求された時に呼ばれる。
@Provides static Heater provideHeater() {
return new ElectricHeater();
}
@Provides
メソッドは自身が依存関係を持つことを可能にする。
以下は、Pumpを要求された時にThermosiphonを返すメソッド。
@Provides static Pump providePump(Thermosiphon pump) {
return pump;
}
全ての@Provides
メソッドはモジュールに所属しなければならない。
モジュールとは@Module
アノテーションを付与したクラスのこと。
@Module
class DripCoffeeModule {
@Provides static Heater provideHeater() {
return new ElectricHeater();
}
@Provides static Pump providePump(Thermosiphon pump) {
return pump;
}
}
@Component
について
@Inject
と@Provides
が付与されたクラスは、それらの依存関係がリンクされたオブジェクトのグラフを形成する。
アプリケーションのメインメソッドやAndroidアプリケーションのようなコードを呼び出すものは、明確に定義された一連のルートを介してグラフにアクセスする。
Dagger2では、その一連は引数を持たないメソッドを持つインターフェースによって定義され、望む型を返す。そのようなインターフェースに対して@Component
アノテーションを付与し、modulesパラメータに対して必要なモジュールクラスを渡す。
Dagger2はそのインターフェースを実装する。
@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
CoffeeMaker maker();
}
その実装はDaggerの接頭辞を持つインタフェースと同じ名前を持つ。
実装上ではbuilder()メソッドを呼ぶことでインスタンスを取得し、返されたbuilderを使い、依存関係をセットし、新しいインスタンスをビルドする。
CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
.dripCoffeeModule(new DripCoffeeModule())
.build();
デフォルトコンストラクタでアクセスできる全てのモジュールはもし何も設定されていなければビルダーが自動的にインスタンスを構築するので削除できる。
モジュールの@Provides
メソッドが全て静的なら、その実装はインスタンスを全く必要としない。
もし、ユーザーが依存関係インスタンスを作成することなく、全ての依存関係が構築できるなら、生成された実装にはcreate()メソッドが用意される。これを使用し、ビルダーを処理せず新しいインスタンスを取得できる。
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
CoffeeAppは注入されたCoffeeMakerを取得するためにCoffeeShopのDaggerに生成された実装を使用できる。
public class CoffeeApp {
public static void main(String[] args) {
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
coffeeShop.maker().brew();
}
}
グラフが構築され、エントリポイントが注入されたので、Coffee Maker Appが実行できる。
$ java -cp ... coffee.CoffeeApp
~ ~ ~ heating ~ ~ ~
=> => pumping => =>
[_]P coffee! [_]P
以上です。