5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DartAdvent Calendar 2014

Day 23

DartでCake PatternによるDI

Last updated at Posted at 2014-12-23

既にDartにはAngularプロジェクト発のDIライブラリがあるのだけれど、
Webブラウザ上での動作時や公開ライブラリ等において、外部ライブラリに依存したくない場合や、そこまで重厚なDIが必要でない場合がままある。
そこで、Dart標準の言語機能で、DIっぽいことをあれこれ試した結果、implicit interfaceとmix-inを使ってCake Patternっぽいものができた。

すごく単純な例で解説。

class Entity {
  String name;
  Entity(this.name);
  String toString() => "Entity:${this.name}";
}

class Repository {
  List<Entity> getAll() =>
      ["entity1", "entity2"].map((s) => new Entity(s)).toList();
}

class Service {
  Repository get repository => new Repository();
  void execute() => print(repository.getAll());
}

EntityインスタンスをRepositoryインスタンスからgetAllメソッドで引っ張ってきてprintするServiceクラスのexecuteメソッドがある。

Serviceクラスのrepositoryプロパティは、プロダクション環境下では以下のクラスを参照したい。

class AwesomeRepository implements Repository {
  List<Entity> getAll() =>
      ["awesomeEntity1", "awesomeEntity2"].map((s) => new Entity(s)).toList();
}

(まぁ実際は外部DBとかにでもアクセスすると思ってください)

もちろん、repositoryプロパティを可変にすれば自在にRepositoryの実装を変更できるのだろうが、そうするとServiceのインタフェースが汚れる。
Dartのimplicit interfaceは便利なのだけれど、意図せぬインタフェースを外部に提供してしまう場合もあるので、クラスやそのメンバーの可視性やオブジェクトの不変性には特に気をつけておきたい。
この例も同様、Serviceの状態は不変を保ちたいとする。

このような場合は、Mix-inを使用する。
以下のようなAwesomeRepositoryへの依存をサポートするためのMix-inを定義して、

abstract class AwesomeRepositoryMixin {
  Repository get repository => new AwesomeRepository();
}

AwesomeRepositoryMixinとのmix-in applicationによって、AwesomeRepositoryへの依存を持つServiceを定義する。

class AwesomeService = Service with AwesomeRepositoryMixin;

(昔はtypedefキーワードだった。しみじみ)

これで、ServiceとAwesomeServiceそれぞれ同じexecuteメソッドを有するが、repositoryプロパティの参照先が変更されため、標準出力の内容がそれぞれで異なる結果が得られる。

main () {
  new Service().execute();
  new AwesomeService().execute();
}

ただ、この方法には、動的にrepositoryプロパティの参照先を変更できないという問題がある。
動的にしたい場合は、constructor injenctionなりproperty injectionなりを採用すればよいと思う。
それよりも、依存関係が複雑化した際のdart analyzerによる静的チェックの恩恵の方が個人的には大きく、この似非Cake patternの採用の動機になっている。

まとめ

  • DIばりばりやりたい場合は、diパッケージ
  • 動的にやりたい場合は、素直にconstructor injenctionかproperty injection
  • 静的に依存関係を構築したい場合は、当記事のCake Pattern
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?