Repository Pattern

고진호·2023년 8월 9일

Repository Pattern

MVVM에서 Model 부분에 해당할 수 있는 패턴으로 데이터 소스 부분과 나머지 부분의 중개자 역할을 한다.이 패턴을 통해서 앱의 나머지 부분이 데이터의 출처에 대해 알 필요가 없게 만든다.

Model에서 Repository Pattern을 사용하게 되면, ViewModel은 Repository를 통해 데이터를 요청하게 되고, Repository는 데이터 소스로부터 데이터를 가져와 ViewModel에 제공하기 때문에 ViewModel은 데이터의 출처나 데이터를 가져오는 방식에 대해 알 필요가 없어지고 Repository하고만 소통할 수 있게 된다.

장점

1. 데이터 소스의 추상화

앱의 나머지 부분과 데이터 소스 사이의 중개자 역할을 하기 때문에 데이터의 실제 출처에 출처나 로직을 알 필요가 없게 된다.

2. 코드의 재사용성

데이터에 접근하는 로직이 Repository 내에 캡슐화되기 때문에 그 방식이 일관되고, 동일한 코드를 여러 곳에서 재사용할 수 있다.

3. 유연성

데이터 소스가 변경되어도 Repository는 그대로 유지되기 때문에, 앱의 다른 부분에 영향을 끼치지 않고 데이터 소스를 제어할 수 있다.

4. 테스트 용이성

Repository를 인터페이스와 구현으로 분리하면, 실제 데이터가 아닌 Mock 데이터 소스를 사용하여 테스트하기 용이하다.

데이터 액세스 로직과 비즈니스 로직이 분리되므로, 각각의 개발에 집중할 수 있다.

단점

1. 오버 엔지니어링

간단하거나 작은 규모의 앱에서 사용하면 오히려개발 시간이 늘어나고, 코드의 복잡성이 증가할 수 있다.

2. 러닝커브

MVVM이나 Repository Pattern과 관련된 아키텍쳐와 개념,사용법을 익히는데 시간이 필요하고 이로 인하여 초기 개발 속도가 느려질 수 있다.

3. 추상화의 오버헤드

모든 데이터 액세스를 추상화 계층을 통해 처리하면, 때로는 성능 오버헤드가 발생할 수 있다. 특히, 복잡한 쿼리나 특정 데이터베이스 최적화 기능을 사용할 때 이런 문제가 발생할 수 있다.

사용 예시(사용자 정보 관리)

UserRepository

//api나 데이터베이스같은 외부 소스가 아닌 메모리에 사용자 정보를 저장,관리
interface UserRepository {
    fun getUserById(idx: Int): User?
    fun getAllUsers(): List<User>
    fun addUser(user: User)
    fun updateUser(user: User)
    fun deleteUser(idx: Int)
}
class InMemoryUserRepository : UserRepository {
    private val users = mutableListOf<User>()

    override fun getUserById(idx: Int): User? {
        return users.find { it.idx == idx }
    }

    override fun getAllUsers(): List<User> {
        return users.toList()
    }

    override fun addUser(user: User) {
        users.add(user)
    }

    override fun updateUser(user: User) {
        val index = users.indexOfFirst { it.idx == user.idx }
        if (index != -1) {
            users[index] = user
        }
    }

    override fun deleteUser(idx: Int) {
        users.removeAll { it.idx == idx }
    }
}

Main

//사용자 정보 CRUD
 fun main() {
        val userRepository: UserRepository = DoUserRepository()

        // 사용자 추가
        userRepository.addUser(User(1, "고진호1", 28))
        userRepository.addUser(User(2, "고진호2", 26))

        // 사용자 조회
        val user1 = userRepository.getUserById(1)
        val user2 = userRepository.getUserById(1)
        Log.d("User1",user1!!.name)
        Log.d("User2",user2!!.name)
        Log.d("User2", user2.age.toString())

        // 모든 사용자 조회
        val allUsers = userRepository.getAllUsers()


        // 사용자 정보 업데이트
        userRepository.updateUser(User(2, "고진호", 26))
        Log.d("User2",user2!!.age.toString())
        // 사용자 삭제
        userRepository.deleteUser(2)
    }
    data class User(val idx: Int, val name: String, val age: Int)

결론

Repository Pattern은 앱 데이터 엑세스 로직과 비즈니스 로직을 분리하여 코드의 유지보수를 향상시키는 중요한 아키텍처 패턴이다.

이 패턴을 통해 앱의 다른 부분은 데이터의 출처나 가져오는 로직에 대해 알 필요 없이 데이터에 접근할 수 있고, 코드의 재사용성이 증가하고 테스트가 용이해지며 , 일관성도 유지할 수 있다.

하지만 큰 규모의 애플리케이션이나 여러가지 데이터 소스의 앱에 사용하는게 유용해보이고 여러가지 단점도 있기 때문에 앱의 규모나 요구사항,팀의 경험/지식수준등 여러 요소를 고려한다면 굉장히 좋은 패턴이라고 생각한다.

profile
Kotlin,Java 안드로이드 앱 개발자 지망생

1개의 댓글

comment-user-thumbnail
2023년 8월 9일

즐겁게 읽었습니다. 유용한 정보 감사합니다.

답글 달기