안드로이드 앱 개발에서 널리 사용되는 아키텍처 패턴 중 하나인 MVVM에 대해서 기록하려고 한다.
요즘 안드로이드 개발을 취미로 시작하여 기록을 위해 작성한다. 혹여나 틀린 정보가 있다면 댓글로 남겨주신다면 반영하겠습니다 감사합니다.
서론
MVVM 패턴이란?
MVVM (Model-View-ViewModel) 패턴은 앱의 UI와 비즈니스 로직을 분리하여 보다 깔끔한 구조와 유지보수성을 제공하는 아키텍처 패턴이다. MVVM은 크게 세 가지 컴포넌트로 구성된다.
- Model: 데이터와 비즈니스 로직을 관리하는 컴포넌트
- View: 사용자에게 보이는 UI
- ViewModel: Model과 View 사이의 중간 역할을 하며, 데이터를 가공하여 View에 전달하고 사용자 인터렉션을 처리
MVVM은 데이터를 UI에 쉽게 바인딩하고, 코드가 모듈화 되어 있어 재사용성과 테스트 용이성을 높이는 데 도움이 된다.
본론
MVVM은 왜 사용할까?
MVVM 패턴을 사용하면 UI와 비즈니스 로직을 명확하게 분리할 수 있다. 이는 특히 앱이 복잡해질수록 개발 및 유지보수에 유리하다.
ViewModel을 활용하면 UI 상태를 관리하고 비즈니스 로직을 처리하는 코드가 분리되어 코드 가독성이 향상되고 테스트가 용이하다.
장점
- UI와 비즈니스 로직의 분리: 코드가 더 구조적이고 이해하기 쉽다.
- 재사용성과 테스트 용이성: ViewModel은 앱의 비즈니스 로직과 데이터를 독립적으로 관리하므로, ViewModel을 별도로 테스트하거나 재사용할 수 있다.
- 데이터 바인딩 지원: ViewModel을 통해 UI와 데이터를 쉽게 바인딩할 수 있어 UI 업데이트가 용이
단점
- 복잡도 증가: 작은 프로젝트에서는 MVVM을 사용하면 오히려 코드가 복잡해질 수 있다.
- 초기 학습 곡선: ViewModel, LiveData 등의 개념을 이해하고 적용하기 위해 다소 높은 학습 곡선이 있다.
예시: Counter 앱에서 MVVM 적용하기
MainActivity - View 초기화 및 ViewModel 구성
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// CounterViewModel 인스턴스 생성
val viewModel: CounterViewModel = viewModel()
// 테마 설정 및 전체 레이아웃 설정
Counter_Theme {
// 배경색을 테마에 따라 설정
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
// Counter 화면을 ViewModel과 함께 호출
TheCounterApp(viewModel)
}
}
}
}
}
- viewModel 함수로 CounterViewModel 인스턴스를 생성해 UI와 연결
- TheCounterApp @Composable에 viewModel을 전달하여 View와 ViewModel을 연결
TheCounterApp - UI
data class CounterModel(var count: Int)
class CounterRepository {
private var _counter = CounterModel(0)
// 현재 카운터 값 반환
fun getCounter() = _counter
// 카운터 증가
fun incrementCounter() {
_counter.count++
}
// 카운터 감소
fun decrementCounter() {
_counter.count--
}
}
- CounterModel은 카운터 값을 저장하는 데이터 클래스
- CounterRepository는 CounterModel의 인스턴스를 관리하고, 카운터 값을 조회하거나 변경하는 메서드를 제공
- incrementCounter()와 decrementCounter() 메서드를 통해 카운터 값을 변경
TheCounterApp - UI
@Composable
fun TheCounterApp(viewModel: CounterViewModel) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// 현재 카운트 값을 표시하는 Text
Text(
text = "Count : ${viewModel.count.value}",
fontSize = 24.sp,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(16.dp))
// 증가와 감소 버튼을 포함한 Row 레이아웃
Row {
Button(onClick = { viewModel.increment() }) {
Text(text = "increment")
}
Button(onClick = { viewModel.decrement() }) {
Text(text = "decrement")
}
}
}
}
- Column과 Row 레이아웃을 사용하여 UI를 구성
- Text로 ViewModel에서 가져온 count 값을 표시하고, increment와 decrement 버튼을 추가하여 값을 변경
- viewModel.increment()와 viewModel.decrement() 함수 호출을 통해 ViewModel의 데이터를 변경
CounterViewModel - ViewModel
class CounterViewModel : ViewModel() {
private val _repository: CounterRepository = CounterRepository()
private val _count = mutableStateOf(_repository.getCounter().count)
// 외부에서 읽기만 가능한 count 상태
val count: MutableState<Int> = _count
// 증가 함수
fun increment() {
_repository.incrementCounter()
_count.value = _repository.getCounter().count
}
// 감소 함수
fun decrement() {
_repository.decrementCounter()
_count.value = _repository.getCounter().count
}
}
- CounterViewModel은 ViewModel을 상속하여 View와 Model 간의 중간 역할
- CounterRepository를 통해 현재 카운터 값을 관리하고, 변경 시 _count를 갱신
- increment와 decrement 함수는 각각 카운터 값을 증가 및 감소시키고, 변경된 값을 count에 반영
결론
MVVM 패턴 요약
MVVM 패턴을 통해 UI와 데이터 로직을 명확하게 분리하고, ViewModel을 통해 데이터를 쉽게 관리할 수 있다. 이 패턴은 특히 UI 변경이 잦거나 비즈니스 로직이 복잡한 앱에서 큰 도움이 된다. 이번 Counter 앱 예제를 통해 MVVM의 구조와 장점을 직접 체험할 수 있으며, 실무에서도 효율적인 아키텍처 패턴으로 활용될 수 있다.
번외
스프링의 MVC패턴과 MVVM 패턴과 상당히 유사한 점을 보여준다.
아래는 이전에 작성한 MVC 관련 글이며, MVC에 대해 잘 모른다면 참고하시길 바랍니다.
2024.11.02 - [Backend/Spring || SpringBoot] - [Spring/스프링] MVC 패턴이란? 스프링 MVC와 Counter 앱 예제
스프링의 MVC 패턴과 비교하기
- Model (MVVM) <-> Service & Repository (Spring)
- MVVM의 Model은 애플리케이션의 데이터를 관리하고, 비즈니스 로직을 처리한다.
- 스프링에서의 Service와 Repository 계층이 이 역할을 한다.
- Repository는 데이터베이스와 상호작용하여 데이터를 가져오고 저장하는 역할을 한다.
- Service는 비즈니스 로직을 담당하며, 여러 데이터 처리를 종합하고 필요한 로직을 구현
- ViewModel (MVVM) <-> Controller (Spring MVC)
- ViewModel은 MVVM에서 View와 Model 사이에서 데이터를 가공하고, UI와 상호작용을 중개하는 역할을 한다.
- 스프링에서는 Controller가 이 역할을 수행
- 스프링의 Controller는 Model과 View 사이에서 요청과 응답을 처리하고, Service와 통신하여 데이터를 가공한 후 View에 전달
- 다만, 스프링의 Controller는 클라이언트의 요청에 응답하는 구조로 동작하고, MVVM의 ViewModel은 상태 관리를 위해 앱의 UI와 긴밀하게 연결되며, 이 점이 큰 차이다.
- View (MVVM) <-> View (Spring - Thymeleaf, JSP 등)
- MVVM의 View는 사용자에게 표시되는 UI로, ViewModel을 통해 데이터와 UI 상태를 바인딩하여 동적 UI를 구성
- 스프링의 View는 템플릿 엔진(Thymeleaf, JSP 등)을 사용하여 Controller로부터 데이터를 받아 사용자에게 표시하는 역할
- 웹 애플리케이션에서는 주로 HTML이나 템플릿 파일을 사용하여 UI를 구성하며, 직접적인 데이터 바인딩보다는 Model을 통해 데이터를 받는다.
'Android > Kotlin' 카테고리의 다른 글
[Kotlin/코틀린] @Parcelize / Parcelable을 사용한 직렬화와 역직렬화 (1) | 2024.11.09 |
---|---|
[Kotlin/코틀린] String과 Int 변환 - String to Int, Int to String 변환 방법 (0) | 2024.11.07 |
[Kotlin/코틀린] 인터페이스와 다중 상속이란? (1) | 2024.11.02 |
[Kotlin/코틀린] override와 super 개념 (1) | 2024.11.02 |