FlutterにおけるRepository Pattern
Repository Patternとは?
アーキテクチャにRepositoryを組み込むパターンです。
Repositoryは、UIやビジネスロジックとは関係ない、ネットワークからデータを所得するような部分です。データの所得だけでなく、データのローカルキャッシングや、取ってきたデータのモデルへの変換等も行います。
Repository Patternのメリット
UI、ビジネスロジックと明確に分けることで、以下のメリットがあります。
- データ所得部分の変更をしても他に影響が出ない
- 型安全性が保証される
例えばデータベースの構造を変更したことで、データ所得のコードも変更されても、UIやビジネスロジックのコードには影響が出ません。
また、型安全性とはType Errorが起きないということです。関数でreturnする型が保証されるので、間違って別の型やnullが返ってくることはありません。
Repository Patternのデメリット
- boilerplate code*が増える
- 学習が少し必要?
*boilerplate code ... 複数の場所で使われる定型コード
Repository Patternを実際に使ってみる
以下のFirebaseUsersRepositoryが今回作ったRepositoryのクラスです。
final usersRepositoryProvider = Provider<FirebaseUsersRepository>((ref) => FirebaseUsersRepository()); class FirebaseUsersRepository { static const int fetchLength = 10; Future<List<UserModel>> fetchUsers( List<String> genderQuery, List<UserModel> before) async { var from = before.isEmpty ? Timestamp.fromDate(DateTime.now()) : before[before.length - 1].timestamp; // Firebaseからデータを所得 QuerySnapshot<Map<String, dynamic>> docs = await FirebaseFirestore.instance .collection('users') .doc('v1') .collection('public') .where('query.gender', whereIn: genderQuery) .orderBy('timestamp', descending: true) .startAfter([from]) .limit(fetchLength) .get(); // 所得したデータをUserModel型のListに変換 String userid = FirebaseAuth.instance.currentUser!.uid; List<UserModel> newList = []; docs.docs.forEach((element) { if (element.exists && element.id != userid && element.data().containsKey('id')) { newList.add(UserModel(element)); } }); return newList; } }
Repositoryクラス内の関数fetchUsersでは、Firebaseからユーザーのデータを10個所得し、UserModel型のListで返します。
1行目のusersRepositoryProviderを通してビジネスロジック側がRepositoryを使うことができます。
List<UserModel> userList = await ref .read(usersRepositoryProvider) .fetchUsers(genderQuery, state.allUsers);
Providerを使っているのは、どこからでもFirebaseUsersRepositoryにアクセスできるようにするためです。
アプリの様々な場所からステートにアクセスできるようになります。 つまり、プロバイダはシングルトンやサービスロケータのようなパターン、依存性注入、あるいはInheritedWidget を完全に代替することができます。 引用元: riverpod.dev
以上です!ありがとうございました。