티스토리 뷰
Data Layer
App전체에 필요한 데이터를 제공하는 곳으로, Repository 패턴으로 구성되어 있다.
보통 ViewModel이 Repository에 필요한 정보를 요청하게 되고, RemoteDataSource, LocalDataSource를 통해 외부혹은 내부스토리지의 데이터를 가져오거나 갱신한다.
Repository
데이터 저장소라는 의미의 Repository는 실제 ViewModel에서 Data Layer에 접근하는 객체이다. 보통은 특정 도메인 별로 Repository를 만들게 되는데 예를 들면 UserRepository, PostRepository와 같은 형태로 구분해서 만든다.
위 에서 확인 할 수 있듯이 ViewModel은 여러 Repository를 참조할 수 있으며, 각 Repository는 그 특성에 따라 LocalDataSource를 참조해서 사용하거나, RemoteDataSource를 참조할 수 있다. 혹은 그 둘다를 사용할 수 도 있다.
# PostRepository (post_repository.dart)
class PostRepository {
final RemoteDataSource _remoteDataSource;
final LocalDataSource _localDataSource;
/// 로컬에 캐싱된 게시물 목록가져옴
Future<List<Post>> getCachedPosts() {
return _localDataSource.getCachedPosts();
}
/// 게시물 목록을 가져옴
Future<List<Post>> getPosts() {
return _remoteDataSource.getPosts();
}
}
DataSource
실제로 사용할 데이터들이 모여 있는 곳으로 크게 로컬 파일이나 로컬 DB에서 저장된 정보를 사용하거나 API서버와 같은 원격저장소에 저장된 정보를 접근해서 사용하게 된다.
LocalDataSource
주로 로컬 DB 연결에 사용된다. 개인적으로 프로젝트에 사용하는 DB라이브러리는 Hive를 사용하는데, Sqlite보다 속도나 사용성 면에서 좋다. (다른 포스팅에서 Hive에 대해 따로 다루도록 하겠다.)
# LocalDataSource (local_data_source.dart)
class LocalDataSource {
/// 캐싱한 게시물을 가져온다.
Future<List<Post>> getCachedPosts() async {
var postBox = await Hive.box<Post>('postBox');
return postBox.values.toList();
}
/// 기존에 캐싱된 게시물들을 모두 삭제하고 새로운 게시물을 캐싱한다.
Future<void> updateCachedPosts(List<Posts> posts) async {
var postBox = await Hive.box<Post>('postBox');
await postBox.clear()
await postBox.addAll(posts)
}
}
위 코드는 LocalDataSource의 역할을 간단히 설명하기 위한 용도이다. 사용하는 DB라이브러리에 따라 함수 구현은 달라질 수 있지만 그 역할은 같을 것이다.
RemoteDataSource
주로 API서버와 통신하는 부분들이 있다.
아래 코드는 http 모듈을 이용해서 API서버로 게시물 목록을 가져오는 예시 코드이다.
# RemoteDataSource (remote_data_source.dart)
class RemoteDataSource {
Future<List<Post>> getPosts() async {
const path = '/api/posts';
const params = <String, String>{};
const uri = Uri.https("flutter_sample.com", path, params);
final res = await http.get(uri);
if (res.statusCode == HttpStatus.ok) {
final data = _bytesToJson(res.bodyBytes) as List;
return data.map((el) => Post.fromMap(el as Map)).toList();
} else {
throw Exception("Error on server");
}
}
}
중.소 규모의 프로젝트는 RemoteDataSource나 LocalDataSource를 하나씩만 있어도 큰 문제는 없다.
왜냐하면 DataSource내부의 함수들은 서로 의존 관계를 가지지 않고, 서로 독립적으로 수행되기 때문에 도메인 별로 클래스를 추가하기 보다 하나의 클래스에 함수들을 늘려가는 방식으로 만들어도 무방하다.
하지만 프로젝트 규모가 커지면 RemoteDataSource와 LocalDataSource도 도메인별로 따로 클래스를 만들어 사용하는 것이 좋을 수도 있다.
지금까지 살펴본 기본적인 구조를 지키며 개발을 하면 복작한 프로젝트도 쉽게 기능을 확장해 나갈수 있을 것이다
> 4부 - 폴더(패키지)구조에서 계속
'Flutter' 카테고리의 다른 글
Flutter 앱개발을 위한 MVVM아키텍처 - 5부 DI와 테스트코드 (7) | 2021.12.01 |
---|---|
Flutter 앱개발을 위한 MVVM아키텍처 - 4부 폴더(패키지) 구조 (10) | 2021.11.29 |
Flutter 앱 개발을 위한 MVVM아키텍처 - 2부 View와 ViewModel (7) | 2021.11.15 |
Flutter 앱 개발을 위한 MVVM아키텍처 - 1부 MVVM이란? (1) | 2021.11.10 |
Flutter main과 비동기 initilize (firebase, intl_utils) (0) | 2021.11.02 |
- Total
- Today
- Yesterday
- flutter l10n
- flutter element
- flutter2.0
- widget element
- LocalKey
- dart enum
- Widget Tree
- enum member
- flutter_secure_storage
- Flutter3.0
- DART
- RenderObject
- navigator
- json_serializable
- Flutter LifeCycle
- StatefulWidget LifeCycle
- flutter i18n
- flutter 다국어처리
- freezed
- Android
- Flutter TDD
- MVVM
- dart 2.17
- flutter mvvm
- Mutiple Flutter
- FlutterEngine
- python3
- Flutter
- Element LifeCycle
- Route
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |