Я сделал несколько комментариев, советовавших об обратном, но я только что вспомнил, что в моем последнем проекте я делал что-то подобное, это было для База данных Firebase , но это было бы очень похоже на sqflite .
Я создал BaseItem
абстрактный класс с key
, и все модели будут наследоваться от него.
Я также создал BaseProvider
абстрактный класс, который будеттребует BaseItem и определяет простые методы для доступа к модели.
Методы upsert
и delete
лежат в FirebaseBaseProvider
, что расширяет BaseProvider
.
Я будувставьте его части сюда (удалив довольно много, чтобы сделать его более понятным):
abstract class BaseItem {
const BaseItem({this.key});
final String key;
}
abstract class BaseProvider<T extends BaseItem> {
Future<List<T>> find();
Future<BaseKey> upsert(T item);
Future<int> delete(T item);
}
abstract class FirebaseBaseProvider<T extends BaseItem> {
// Abstract methods which need to be implemented
T fromMap(BaseKey key, dynamic map);
Map<String, dynamic> toJson(BaseKey key, T item);
Future<DatabaseReference> getReference(BaseKey base) async { ... }
BaseKey compileKey(T item, {String useKey}) { ... }
Future<List<T>> find() async {
List<T> result = new List();
// my implementation doesnt work like this,
// as it's firebase based, but this would
// be the place in a Sqflite implementation to use
// fromMap and load the items
return result;
}
Future<BaseKey> upsert(T item) async {
if (item == null) return null;
BaseKey key = compileKey(item);
(await getReference(key)).set(toJson(key, item));
return key;
}
Future<int> delete(T item) async {
if (item == null) return null;
if (item.key != null && item.key != "") {
(await getReference(compileKey(item))).remove();
}
return 0;
}
}
Затем, чтобы реализовать модель News
или любую другую модель, я бы создал ее простоопределяя его содержимое следующим образом:
class News extends BaseItem {
News({String key, this.creation, this.messageSubject, this.messageBody}) : super(key: key);
final DateTime creation;
final String messageSubject;
final String messageBody;
bool operator ==(o) => o is News && (o.key == key);
int get hashCode => key.hashCode;
}
И для этого потребуется специальный поставщик, который будет реализовывать только методы toJson
и fromMap
, например:
class NewsProvider extends FirebaseBaseProvider<News> {
@override
Map<String, dynamic> toJson(BaseKey key, News news) {
return {
"creation": news.creation,
"messageSubject": news.messageSubject,
"messageBody": news.messageBody,
};
}
@override
News fromMap(BaseKey key, dynamic map) {
DateTime creation = map["creation"] == null ? null : DateTime.tryParse(map["creation"] as String);
return new News(
key: key.child.key,
creation: creation,
messageSubject: map["messageSubject"] as String,
messageBody: map["messageBody"] as String,
);
}
}
В конце концов, NewProvider
предоставляет метод find
, upsert
и delete
ds, но их реализация лежит на абстрактном классе, только одна их реализация для всех моделей, как вы и хотели.
Конечно, моя реализация более сложна, чем обе, потому что Firebase требует другого подходадля получения / загрузки элементов, а также в результате того, что метод find
должен быть разным в каждой конкретной модели поставщика.Но, тем не менее, многое можно упростить.
Что я говорил в комментарии, так это то, что этот последний класс, специфические NewsProvider
, которые имеют как toJson
, так и fromMap
конкретные реализации, также могут быть обобщеныиспользуя аннотации в классе модели News
, но это приносит много проблем и неясности и - на мой взгляд, конечно - это того не стоит.