🍼

【Dart】DIコンテナなしで依存性の逆転してみる

2024/02/02に公開

まえがき

私は普段業務でJavaかKotlinとSpringBootの組み合わせで開発を行っています。
個人開発では最近Flutterでアプリを作り始めています。DartでもDIというか、依存性の逆転を実現したいと思いました。どうやらDartにはDIコンテナは無いみたいなので自力でやってみようと思います。

実装してみる

抽象クラス

抽象クラスに具象クラスのインスタンスを持つことにしました。

// 抽象クラス、抽象クラスでインスタンスを保持する。
abstract interface class CalcService {
  int add(int a, int b);
  
  int subtract(int a, int b);
  
  int multiply(int a, int b);
  
  int divide(int a, int b);
  
  // 具象クラスの入れ物
  static late final CalcService _instanse;
  
  static void inject(CalcService inst) {
    _instanse = inst;
  }
  
  static CalcService getInstace() {
    return _instanse;
  }
}

具象クラス

抽象クラスを実装した具象クラスです。

// 具象クラス
class CalcServiceImpl implements CalcService {
  
  int add(int a, int b) {
    return a + b;
  }

  
  int subtract(int a, int b) {
    return a - b;
  }

  
  int multiply(int a, int b) {
    return a * b;
  }

  
  int divide(int a, int b) {
    return (a / b) as int;
  }
}

初期化

初期化では具象クラスのインスタンスの生成を行います。
生成したインスタンスは抽象クラスがもつフィールドに入れておきます。

// アプリケーションが起動するときに呼ばれる
class Initializer {
  void init() {
    // 具象クラスのインスタンスを抽象クラスにセットする。
    // 依存性の注入
    CalcService.inject(CalcServiceImpl());
  }
}

CalcServiceを使う

void main() {
  // 初期化(依存性の注入)
  Initializer().init();

  // 抽象クラス経由でインスタンスを取得する。
  final CalcService service = CalcService.getInstace();

  // インスタンスを使う
  print(service.add(1, 1));
  print(service.multiply(4, 2));
}

クラス図

なんで依存性の逆転したかったんだっけ?

バックエンドの実装がFirebaseだったり、Supabaseだったり、自分でSpring使って実装したり、さまざまな構成を試した見たくて、実装が変わる可能性があったからです。

あくまでバックエンドの勉強のために差し替えるだけですが。
バックエンドの勉強なので、「バックエンドを変えたから、画面のコードにも手を入れないと!」なんてならないためです。

今回のパターンだとCalcServiceImplとInitializerを書き換えればバックエンドは差し替えることができますね。

所感

Spring FrameworkのDIコンテナってやっぱりすごい!

Discussion