DIコンテナとは
インスタンスの生成方法を知っているもの。
利用者はインスタンスの作成方法を知らなくてもいい。
インターフェースを用意して、実装とモックを切り替えたり、シングルトンを作ったりできる。
DIコンテナの作成
Laravelのサービスコンテナを参考にしました。
class Container {
/// Typeをキーにするのがみそ
static final Map<Type, Object Function()> _container = {};
/// シングルトン
static final Container _singleton = Container._();
factory Container() {
return _singleton;
}
Container._();
/// インスタンスの生成方法を登録
bind<T>(T Function() bind) {
_container[T] = bind;
}
/// シングルトン登録
singleton<T>(T singleton) {
_container[T] = () => singleton;
}
// T型のインスタンスを自動で作成
T make<T>() => _container[T]();
}
つかう
クラスの作成
class Hoge{
String getHoge() => "hoge";
}
class Api{
Future<String> getJsonData() async{
final response = await http.get('https://jsonplaceholder.typicode.com/todos/1');
return response.body;
}
}
class ApiMock implements Api{
@override
Future<String> getJsonData() async{
return '{"userId": 1,"id": 1,"title": "delectus aut autem","completed": false}';
}
}
コンテナに登録
main(bool debug) {
final container = Container();
// Hogeインスタンスの登録
container.bind<Hoge>(() => Hoge());
if (debug) {
// デバッグがONのときはモックを登録
// bindのジェネリクスにインターフェースになる側のApiを指定しておくのがみそ
container.bind<Api>(() => ApiMock());
} else {
// 通常時
container.bind<Api>(() => Api());
}
}
DIの仕方
class HogeWidget extends StatelessWidget {
// 自動的に型に合わせたインスタンスを生成してくれる
// Apiがモックかどうかに依存せずに使える
final Api _api = Container().make();
final Hoge _hoge = Container().make();
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _api.getJsonData(),
builder: (context, snapShot) {
if (!snapShot.hasData) return CircularProgressIndicator();
return Text(_hoge.getHoge() + snapShot.data);
},
);
}
}