[Android] kotlin MVVM 패턴의 정의, MVC 패턴과 차이점도 알아보자

하은·2024년 2월 13일
0

Android

목록 보기
1/4

기존 회사 소스코드에서는 정확한 디자인패턴을 적용시키고 있지않았는데, 마침 어느정도 프로젝트가 안정화되면서 나 스스로 개발할 수 있는 시간이 주어졌다.
기존 코드에서는 명확하게 정의된 디자인 패턴이 없었어서, 그 시간동안 디자인 패턴중 가장 대중적으로 많이 사용되는 MVVM 패턴을 도입해보기로 결정했다.

MVVM 패턴이란 ?

MVVM패턴은 크게 세가지 M(model), V(view), VM(viewmodel)로 구분하여 설계하는 디자인 패턴이다.

Model (모델):

  • 데이터와 비즈니스 로직을 포함
  • 일반적으로 데이터베이스나 외부 서비스와 상호 작용하여 데이터를 가져오고 업데이트
  • 사용자 인터페이스와는 독립적으로 존재하며, 보통 도메인 객체나 데이터 전송 객체로 표현

View (뷰):

  • 사용자에게 데이터를 표시하고 사용자 입력을 수신하는 역할
  • 사용자 인터페이스를 생성하고 업데이트
  • 주로 UI 컴포넌트로 구성되며, 화면에 표시되는 모든 것을 포함
  • 사용자가 보는 UI 부분으로, 레이아웃 파일(.xml) 뿐만 아니라 Activity, Fragment등도 View로 분류

ViewModel (뷰 모델):

  • 사용자 인터페이스의 상태와 동작을 추상화
  • View에 표시되는 데이터를 보유하고, View의 상태를 조작
  • Model로부터 데이터를 가져와서 View에 바인딩하고, View에서 발생하는 이벤트를 처리
  • View와 Model 간의 중간 계층으로 작동하여, View와 Model 사이의 직접적인 의존성을 줄임
  • 보통 특정 View에 종속되지 않고 재사용 가능한 형태로 설계
  • LiveData나 DataBinding을 사용하여 View와의 의존성을 제거할 수 있음
  • 간단하게 설명하자면 model 쪽에서는 서버와 데이터와 관련된 로직 부분을 담당하고, view는 사용자와 의사소통하기 위해 표현된 ui와 관련된 로직 부분을 담당, viewModel은 ui에서 사용자의 반응이 있을 때 model에서 데이터를 가져오는 등등 view와 model 사이에서 발생하는 이벤트들을 처리하는 부분을 담당한다.

이렇게 세개의 관심사를 확실히 분리하면서 서로 계층간의 의존성을 낮춰줄 수 있다.

동작 과정:

  1. 사용자 입력이 발생하면 View가 이를 ViewModel에 전달
  2. ViewModel은 필요한 작업을 수행하고, 필요에 따라 Model에 데이터를 요청
  3. Model은 데이터를 제공하고 ViewModel은 이를 가공하여 View에 전달
  4. View는 ViewModel에서 제공한 데이터를 표시하고, 사용자에게 피드백을 제공
  5. View에서 발생하는 이벤트는 ViewModel에 전달되어 처리

MVC 패턴과 MVVM 패턴의 차이점은 뭘까?


출저 : https://blog.yena.io/studynote/2019/03/16/Android-MVVM-AAC-1.html

MVVM 패턴은 MVC 패턴의 Controller와 View, MVP 패턴의 Presenter와 View 사이의 의존성의 문제를 해결하기 위해 ViewModel이라는 개념을 도입한 것이다.

ViewModel을 도입하면서 가장 차이점을 드러내는 부분
1. 양방향 통신
2. View와의 의존성 없음 (ViewModel은 View를 참조하지 않음)
3. View와 ViewModel은 1:n 관계를 가질 수 있음

ViewModel 구현 예제

사용자가 주사위를 굴려 화면에 나타내는 간단한 예제를 보자면

  1. ViewModel의 구현
data class DiceUiState(
    val firstDieValue: Int? = null,
    val secondDieValue: Int? = null,
    val numberOfRolls: Int = 0,
)

class DiceRollViewModel : ViewModel() {

    // Expose screen UI state
    private val _uiState = MutableStateFlow(DiceUiState())
    val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()

    // Handle business logic
    fun rollDice() {
        _uiState.update { currentState ->
            currentState.copy(
                firstDieValue = Random.nextInt(from = 1, until = 7),
                secondDieValue = Random.nextInt(from = 1, until = 7),
                numberOfRolls = currentState.numberOfRolls + 1,
            )
        }
    }
}
  1. Activitiy의 구현
import androidx.activity.viewModels

class DiceRollActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same DiceRollViewModel instance created by the first activity.

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val viewModel: DiceRollViewModel by viewModels()
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Update UI elements
                }
            }
        }
    }
}

ViewModel의 권장사항

  1. 재사용 가능한 UI 구성요소의 상태 홀더로 사용해선 안됨. 그러지 않으면 동일한 ViewModelStoreOwner의 동일한 UI 구성요소를 다른 방식으로 사용할 때 동일한 ViewModel 인스턴스가 생성됨.
  2. ViewModel은 UI 구현 세부정보에 관해 알 수 없음. ViewModel API가 노출하는 메서드의 이름과 UI 상태 필드의 이름을 최대한 일반적으로 유지해야함.
  3. ViewModelStoreOwner보다 오래 지속될 수 있으므로 ViewModel은 메모리 누수를 방지하기 위해 Context 또는 Resources와 같은 수명 주기 관련 API의 참조를 보유해서는 안됨.
  4. ViewModel을 다른 클래스, 함수 또는 기타 UI 구성요소에 전달하면 안됨. 플랫폼에서 이를 관리하므로 최대한 가깝게 유지해야 합니다. 활동이나 프래그먼트, 화면 수준의 구성 가능한 함수 가까이 유지해야함.

참고 : https://developer.android.com/topic/libraries/architecture/viewmodel?hl=ko

profile
하니의 개발 블로그

0개의 댓글