在 flutter bloc 中使用松散耦合的本地数据存储库
Using loosely coupled local data repositories in flutter bloc
这是一个什么是最佳实践的问题。
我正在使用 flutter 构建一个应用程序,我有以下要求。
我有本地(安装在设备上)和远程(安装在服务器上)数据库。
我必须为本地数据库构建存储库。我对此有很多选择(SQLITE、Hive 等)。我必须保持数据库的选择与应用程序松耦合(存储库模式)。
我必须使用 BLOC 模式进行状态管理。
我挣扎的地方是对于每种类型的数据库,实体模型(我来自 entity framework 背景,因此称它为实体模型。我不知道你怎么称呼它)是不同。
例如,
SQLLite (Moor) 的模型如下所示
class ToDosSqlLite extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
}
Hive 的模型如下所示。
class ToDosHive extends HiveObject {
final int id;
final String title;
Person(this.id, this.title);
}
对于任何其他数据库选择,模型看起来会有所不同。
我有存储库 类 如下。
abstract class LocalToDoRepository{
List<What should be the type here?> getAll();
}
class SqlLiteToDoRepository extends LocalToDoRepository{
///overriding won't work here as Type is different from the base class method
@override
List<ToDosSqlLite> getAll(){///implementation}
}
class HiveToDoRepository extends LocalToDoRepository{
///overriding won't work here as Type is different from the base class method
@override
List<ToDosHive> getAll(){///implementation}
}
在 SqlLiteToDoRepository 中,一个 getAll()
方法 returns 一个 List<ToDosSqlLite>
和在 HiveToDoRepository 中,相同的方法 returns 一个 List<ToDosHive>
.
下面是我的Bloc
class ToDoBloc extends Bloc<ToDoEvent, ToDoState>{
final LocalToDoRepository localToDoRepository;
///localToDoRepository object is dependency injected . If I want to use SQLite, I will inject
///SqlLiteToDoRepository and so on.
ToDoBloc ({@required this.localToDoRepository}): super(ToDoInitialState());
}
如何优雅地进行抽象?大家有什么想法请多多指教
提前致谢。
您可能需要介绍第三个 class 名为 todo
class Todo {
final int id;
final String title;
Todo(this.id, this.title);
// implement the required conversion
Todo.fromHive(......)
Todo.fromSqf(.....)
}
然后,在所有 repos 和接口中使用这个新模型
您可以尝试这样的操作:
final _mockedSql = [
ToDoSqlLite(1, 'Implement dependency inversion principle'),
ToDoSqlLite(2, 'Implement repository pattern'),
];
final _mockedHive = [
ToDoHive(1, 'Feed the cat'),
ToDoHive(2, 'Wash dishes'),
];
abstract class ToDoBase<A, B> {
abstract final A id;
abstract final B title;
}
class ToDoBusinessEntity {
final int id;
final String title;
ToDoBusinessEntity(this.id, this.title);
@override
String toString() => 'ToDoBusinessEntity {id: $id, title: $title}';
}
class ToDoSqlLite implements ToDoBase<int, String> {
final int id;
final String title;
ToDoSqlLite(this.id, this.title);
}
class ToDoHive implements ToDoBase<Object, Object> {
final Object id;
final Object title;
ToDoHive(this.id, this.title);
}
abstract class LocalToDoRepository<T extends ToDoBase, Z>{
abstract final DataSource<T> dataSource;
List<Z> getAll();
List<Z> _sourceToEntity(List<T> sourceList);
}
abstract class DataSource<T> {
List<T> getAll();
}
class SqlDataSource implements DataSource<ToDoSqlLite> {
List<ToDoSqlLite> getAll() => _mockedSql;
}
class HiveDataSource implements DataSource<ToDoHive> {
List<ToDoHive> getAll() => _mockedHive;
}
class SqlLiteToDoRepository implements LocalToDoRepository<ToDoSqlLite, ToDoBusinessEntity>{
DataSource<ToDoSqlLite> dataSource;
SqlLiteToDoRepository(this.dataSource);
@override
List<ToDoBusinessEntity> _sourceToEntity(List<ToDoSqlLite> source) => source.map<ToDoBusinessEntity>((e) => ToDoBusinessEntity(e.id, e.title)).toList();
@override
List<ToDoBusinessEntity> getAll() => _sourceToEntity(dataSource.getAll());
}
class HiveToDoRepository implements LocalToDoRepository<ToDoHive, ToDoBusinessEntity>{
DataSource<ToDoHive> dataSource;
HiveToDoRepository(this.dataSource);
@override
List<ToDoBusinessEntity> getAll() => _sourceToEntity(dataSource.getAll());
@override
List<ToDoBusinessEntity> _sourceToEntity(List<ToDoHive> source) => source.map<ToDoBusinessEntity>((e) => ToDoBusinessEntity(int.parse(e.id.toString()), e.title.toString())).toList();
}
class Bloc {
final LocalToDoRepository repository;
Bloc(this.repository) {
print(repository.getAll());
}
}
void main() {
final blocSql = Bloc(SqlLiteToDoRepository(SqlDataSource()));
final blocHive = Bloc(HiveToDoRepository(HiveDataSource()));
}
这输出
[ToDoBusinessEntity {id: 1, title: Implement dependency inversion principle}, ToDoBusinessEntity {id: 2, title: Implement repository pattern}]
[ToDoBusinessEntity {id: 1, title: Feed the cat}, ToDoBusinessEntity {id: 2, title: Wash dishes}]
这是一个什么是最佳实践的问题。
我正在使用 flutter 构建一个应用程序,我有以下要求。
我有本地(安装在设备上)和远程(安装在服务器上)数据库。
我必须为本地数据库构建存储库。我对此有很多选择(SQLITE、Hive 等)。我必须保持数据库的选择与应用程序松耦合(存储库模式)。
我必须使用 BLOC 模式进行状态管理。
我挣扎的地方是对于每种类型的数据库,实体模型(我来自 entity framework 背景,因此称它为实体模型。我不知道你怎么称呼它)是不同。
例如,
SQLLite (Moor) 的模型如下所示
class ToDosSqlLite extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 32)();
}
Hive 的模型如下所示。
class ToDosHive extends HiveObject {
final int id;
final String title;
Person(this.id, this.title);
}
对于任何其他数据库选择,模型看起来会有所不同。
我有存储库 类 如下。
abstract class LocalToDoRepository{
List<What should be the type here?> getAll();
}
class SqlLiteToDoRepository extends LocalToDoRepository{
///overriding won't work here as Type is different from the base class method
@override
List<ToDosSqlLite> getAll(){///implementation}
}
class HiveToDoRepository extends LocalToDoRepository{
///overriding won't work here as Type is different from the base class method
@override
List<ToDosHive> getAll(){///implementation}
}
在 SqlLiteToDoRepository 中,一个 getAll()
方法 returns 一个 List<ToDosSqlLite>
和在 HiveToDoRepository 中,相同的方法 returns 一个 List<ToDosHive>
.
下面是我的Bloc
class ToDoBloc extends Bloc<ToDoEvent, ToDoState>{
final LocalToDoRepository localToDoRepository;
///localToDoRepository object is dependency injected . If I want to use SQLite, I will inject
///SqlLiteToDoRepository and so on.
ToDoBloc ({@required this.localToDoRepository}): super(ToDoInitialState());
}
如何优雅地进行抽象?大家有什么想法请多多指教
提前致谢。
您可能需要介绍第三个 class 名为 todo
class Todo {
final int id;
final String title;
Todo(this.id, this.title);
// implement the required conversion
Todo.fromHive(......)
Todo.fromSqf(.....)
}
然后,在所有 repos 和接口中使用这个新模型
您可以尝试这样的操作:
final _mockedSql = [
ToDoSqlLite(1, 'Implement dependency inversion principle'),
ToDoSqlLite(2, 'Implement repository pattern'),
];
final _mockedHive = [
ToDoHive(1, 'Feed the cat'),
ToDoHive(2, 'Wash dishes'),
];
abstract class ToDoBase<A, B> {
abstract final A id;
abstract final B title;
}
class ToDoBusinessEntity {
final int id;
final String title;
ToDoBusinessEntity(this.id, this.title);
@override
String toString() => 'ToDoBusinessEntity {id: $id, title: $title}';
}
class ToDoSqlLite implements ToDoBase<int, String> {
final int id;
final String title;
ToDoSqlLite(this.id, this.title);
}
class ToDoHive implements ToDoBase<Object, Object> {
final Object id;
final Object title;
ToDoHive(this.id, this.title);
}
abstract class LocalToDoRepository<T extends ToDoBase, Z>{
abstract final DataSource<T> dataSource;
List<Z> getAll();
List<Z> _sourceToEntity(List<T> sourceList);
}
abstract class DataSource<T> {
List<T> getAll();
}
class SqlDataSource implements DataSource<ToDoSqlLite> {
List<ToDoSqlLite> getAll() => _mockedSql;
}
class HiveDataSource implements DataSource<ToDoHive> {
List<ToDoHive> getAll() => _mockedHive;
}
class SqlLiteToDoRepository implements LocalToDoRepository<ToDoSqlLite, ToDoBusinessEntity>{
DataSource<ToDoSqlLite> dataSource;
SqlLiteToDoRepository(this.dataSource);
@override
List<ToDoBusinessEntity> _sourceToEntity(List<ToDoSqlLite> source) => source.map<ToDoBusinessEntity>((e) => ToDoBusinessEntity(e.id, e.title)).toList();
@override
List<ToDoBusinessEntity> getAll() => _sourceToEntity(dataSource.getAll());
}
class HiveToDoRepository implements LocalToDoRepository<ToDoHive, ToDoBusinessEntity>{
DataSource<ToDoHive> dataSource;
HiveToDoRepository(this.dataSource);
@override
List<ToDoBusinessEntity> getAll() => _sourceToEntity(dataSource.getAll());
@override
List<ToDoBusinessEntity> _sourceToEntity(List<ToDoHive> source) => source.map<ToDoBusinessEntity>((e) => ToDoBusinessEntity(int.parse(e.id.toString()), e.title.toString())).toList();
}
class Bloc {
final LocalToDoRepository repository;
Bloc(this.repository) {
print(repository.getAll());
}
}
void main() {
final blocSql = Bloc(SqlLiteToDoRepository(SqlDataSource()));
final blocHive = Bloc(HiveToDoRepository(HiveDataSource()));
}
这输出
[ToDoBusinessEntity {id: 1, title: Implement dependency inversion principle}, ToDoBusinessEntity {id: 2, title: Implement repository pattern}]
[ToDoBusinessEntity {id: 1, title: Feed the cat}, ToDoBusinessEntity {id: 2, title: Wash dishes}]