Repository 패턴 적용
기존에는 MainService가 외부 서버에서 데이터를 받아와 MainActivity에게 전달해줬었다.
MainService안에서 Retrofit를 활용해 한 번에 데이터를 불러왔지만
Repository 패턴을 적용하여 데이터 로드 과정을 계층화하려고 한다.
UI 레이어의 MapViewModel이 데이터 레이어의 MaskAlarmiRepository에게 Store 리스트를 요청했다.
그 순간 데이터 레이어에서는 어떤 일이 생기는 걸까?
데이터 레이어에서는 UI 레이어가 요청한 데이터만 잘 전달하면 된다.
UI는 데이터의 출처가 어디인지 몰라도 된다.
레포지토리는 외부 저장소인지 내부 저장소인지를 선택해 저장소에서 데이터를 요청한다.
저장소에서 가져온 데이터를 UI 레이어에게 필요한 데이터로 가공해서 전달해주면 된다.
즉, 레포지토리는 중간 저장소 및 가공의 역할을 담당하게 된다.
class MaskAlarmiRepository private constructor(private val context: Context) {
private val maskAlarmiDB: MaskAlarmiDB = Room.databaseBuilder(
context.applicationContext,
MaskAlarmiDB::class.java,
MASK_ALARMI_DB_NAME,
).build()
private val storeLocalDataSource = maskAlarmiDB.storeDao()
fun getStoresByGeo(
lat: Double,
lng: Double,
m: Int,
onSuccess: (List<Store>) -> Unit,
onFailure: (String) -> Unit
) {
GlobalScope.launch(Dispatchers.IO) {
try {
val stores = storeLocalDataSource.getStoresByGeo()
val storesInRadius = stores.filter { store ->
GeoUtil.calculateHaversine(lat, lng, store.lat, store.lng) <= m.toDouble()
}.map { it.toModel() }
onSuccess(storesInRadius)
} catch (e: Exception) {
onFailure("${e.message}")
}
}
}
}
MaskAlarmiRepository에서 안드로이드 SQLite에 접근할 수 있는 MaskAlarmiDB 객체를 생성하고
Store 테이블에 접근할 수 있는 Dao 구현체인 StoreLocalDataSource를 초기화했다.
MaskAlarmiRepository의 getStoresByGeo 메서드를 호출하면
StoreLocalDataSource의 getStoresByGeo를 호출해 기기 내부 DB에 저장된 Store 데이터들을 불러왔다.
데이터를 ViewModel 에게 전달하기 전 가공 단계가 있다.
- 인자로 받은 위도, 경도의 중심 반경 1km 내 Store 데이터 필터링
- StoreEntity의 데이터를 Store 데이터로 필터링
위 두 단계를 거쳐 UI 레이어에게 필요한 데이터로 가공한 뒤
인자로 받은 콜백 함수를 통해 성공 실패에 따라 해당 함수를 호출해줌으로써
MapViewModel 에게 결과를 최종적으로 알려주었다.
(공적 마스크 API로 원격 서버에서 데이터를 불러올 때는
위경도와 반경 데이터를 전달해 자동으로 중심 반경 내 데이터를 불러왔지만
현재는 더미 데이터를 기기 DB에 저장해놓고 사용해서
레포지토리가 로컬 저장소를 이용하고
위경도 중심 반경 내 데이터를 계산하는 로직을 넣어줘서 공적 마스크 API를 사용한 것처럼 재현했다.)
package com...mask_alarmi.data.local.entities
@Entity(tableName = "stores")
data class StoreEntity (
@PrimaryKey val code: String,
val lat: Double,
val lng: Double,
val addr: String,
val name: String,
val type: String,
val remain_stat: String?,
val stock_at: String?,
val created_at: String?,
) {
fun toModel(): Store = Store(
code = code.toLong(),
name = name,
address = addr,
lat = lat,
lng = lng,
remainState = RemainState.fromValue(remain_stat),
stockAt = stock_at,
)
}
실제 공적 마스크 API의 판매처 데이터 모델이다.
StoreEntity는 내부 DB에 저장되는 목적의 데이터 클래스이다.
실제 공적 마스크 API를 사용했으면 원격 저장소에서 왔다는 의미로
StoreDTO로 네이밍했을 것 같다.
toModel 메서드는 UI 레이어에서 필요한 속성만을 가진 객체로 필터링해준다.
이렇게 데이터 클래스안에서 어플리케이션에 사용할 데이터 모델로
변환해주는 Mapper 함수를 설정하고 레포지토리에서 가공해줄 수 있다.
'프로젝트 > 마스크 알라미' 카테고리의 다른 글
4년 전 코드 리팩토링하기 (3) - MVVM 패턴 (0) | 2023.10.29 |
---|---|
4년 전 코드 리팩토링하기 (2) - 아키텍처 재설계 (0) | 2023.10.26 |
4년 전 코드 리팩토링하기 (1) (0) | 2023.10.20 |