Flutterだとリフレクションができないので、自作の薄いORMとが作りづらいのですが、リフレクションなしで汎用的にする方法を紹介します。
Nappsではこの方法を使ってfirestoreの薄いラッパークラスを作っています。
リフレクションできないと何が面倒なのか?
Mapから生成できるEntityBaseを用意したときに、共通のRepositoryクラスでEntityクラスのfromMapを実行しエンティティのインスタンスが取得できたら便利そうですが、スタティックメソッドをジェネリクスを使って呼び出すことはできません。またFlutterではリフレクションもできないため、直接呼び出すこともできません。
abstract class EntityBase {
factory Entity.fromMap(Map map);
Map toMap();
}
実際のエンティティのサンプル
class SampleEntity extends EntityBase {
final String name;
SampleEntity({@required this.name}
factory Entity.fromMap(Map map) => SampleEntity(name: map['name'])
Map toMap() => {
'name': name
}
}
Builderクラスを使ってインスタンスを生成する
fromMapがスタティックメソッドになっているためジェネリクスに対応できないので、fromMapをインスタンスメソッドでラップしたBuilderクラスを用意します
abstract class Builder<T> {
T build(Map);
}
実際のビルダークラスのサンプル
class SampleEntityBuilder extends BuilderBase<SampleEntity> {
SampleEntity build(Map map) => SampleEntity.fromMap(map);
}
Builderでラップすることで、builder.build(map)のように呼び出すことでエンティティのインスタンスを取得できるようになります
Repository
Repositoryはbuilderを受け取ることで、mapからエンティティへの変換が必要になったときに、builder.build(map)を実行するだけで、エンティティのインスタンスを取得することができます。
abstract class RepositoryBase<T extends EntityBase, S extends BuilderBase> {
final S builder;
RepositoryBase(this.builder);
}
エンティティごとに用意するコード
エンティティごとに用意するコードをまとめると下記の3つになります
class SampleEntity extends EntityBase {
final String name;
SampleEntity({@required this.name}
factory Entity.fromMap(Map map) => SampleEntity(name: map['name'])
Map toMap() => {
'name': name
}
}
class SampleEntityBuilder extends BuilderBase<SampleEntity> {
SampleEntity build(Map map) => SampleEntity.fromMap(map);
}
class SampleRepository extends RepositoryBase<SampleEntity, SampleBuilder> {
SampleRepository(): super(SampleEntityBuilder());
}