👏

riverpod_generatorで依存性注入(DI)

2023/11/27に公開

はじめに

riverpod_generatorを導入すると、各providerの書き方が大きく変わってしまうので、その場合で依存性注入(DI)を構築する方法を紹介したいと思います。

記事の対象者

  • 依存性注入(DI)に馴染みのある方

  • riverpodで依存性注入を構築したい方

  • riverpod_generatorを利用したい方

riverpodにおけるDI

その前に、まずはriverpodのみで依存性注入をやってみましょう。

実装例

final engineAProvider = Provider<Engine>((_) => EngineA());
final engineBProvider = Provider<Engine>((_) => EngineB());

abstract class Engine {
  void start() {}
}
class EngineA implements Engine {
  
  void start() {
    debugPrint('Engine A started.');
  }
}
class EngineB implements Engine {
  
  void start() {
    debugPrint('Engine B started.');
  }
}

final carAProvider = Provider((ref) => Car(engine: ref.watch(engineAProvider)));
final carBProvider = Provider((ref) => Car(engine: ref.watch(engineBProvider)));

class Car {
  const Car({required this.engine});

  final Engine engine;

  void drive() {
    engine.start();
  }
}

実行結果

// Print: Engine A started.
ref.read(carAProvider).drive();

// Print: Engine B started.
ref.read(carBProvider).drive();

上記の通り、ProviderでEngineのインスタンスを提供してCarに渡しています。

Engineを生成するProviderを変えることで、異なるEngineを持つCarを作ることが可能になります。

このようにDIを行うことで、テストが容易になり、変化に強いアプリを作りやすくなります。

riverpod_generatorを利用したDI

さーて、riverpod_generatorの場合はどうすれば良いのでしょうか?

実装例

abstract class Engine {
  void start() {}
}

(keepAlive: true)
class EngineA extends _$EngineA implements Engine {
  
  Engine build() => this;

  
  void start() {
    debugPrint('Engine A started');
  }
}
(keepAlive: true)
class EngineB extends _$EngineB implements Engine {
  
  Engine build() => this;

  
  void start() {
    debugPrint('Engine B started');
  }
}

(keepAlive: true)
Car carA(CarARef ref) => Car(engine: ref.watch(engineAProvider));
(keepAlive: true)
Car carB(CarBRef ref) => Car(engine: ref.watch(engineBProvider));

class Car {
  const Car({required this.engine});

  final Engine engine;

  void drive() {
    engine.start();
  }
}

実行結果

// Print: Engine A started.
ref.read(carAProvider).drive();

// Print: Engine B started.
ref.read(carBProvider).drive();

EngineAEngineBそれぞれをProviderClassに変更し、CarACarBを生成するProviderを再作成します。

それで、マイグレーションする前と全く同じ仕組みを作ることができました。

さいごに

この記事では、riverpod_generatorを利用した依存性注入(DI)を構築する方法を紹介しました。

現時点でriverpod_generatorはoptionの扱いになるのですが、作者のRemiさんは

riverpod_generatorは未来に向けた仕組みで、少し不便なところもあるのですが使うのをおすすめします。

述べているため、未来に備えてどんどん使っていきましょう。

GitHubで編集を提案

Discussion