개요
컴포즈 프로젝트를 진행하면서 MVI 아키텍처에 대해 계속해서 접하고 있다. 왜 쓰는지? 다른 아키텍처랑 차이가 무엇인지?에 대해 정확하게 알고 갈 필요가 있다고 생각해서 일단 MVC, MVP, MVVM 아키텍처에 대해 정리하고 가야겠다.
1. MVC
MVC는 안드로이드 앱에서 가장 기초적인 아키텍처 패턴이다. Model, View, Controller로 구성되는데 안드로이드에서는 Activity가 View와 Controller에 역할을 한다.
각 역할에 대해 알아보자
Model
-> 애플리케이션의 데이터 및 비즈니스 로직을 담당한다. 즉, 데이터베이스나 서버와의 통신, 데이터 처리 등의 역할을 맡는다.
View
-> UI를 말한다.
-> View의 경우 controller의 존재를 알지 못하고, Model만 알고 있다
-> Model에서 넘어온 데이터를 가지고 View를 그린다.
Controller
-> 사용자의 Input을 입력 받고, 그에 따라 Model을 변경한다.
-> View를 직접 조정하지 않는다.
주의점
View의 경우 Model이 전달되기를 기다리는데, 그 과정에서 Controller를 거치지 않아 아래와 같은 방법을 써야 한다.
1. Model이 데이터의 변화를 View에게 직접 알린다.
2. View가 주기적으로 Model을 가져와 업데이트한다. -> Polling
이 방법들 같은 경우 안드로이드에서 사용하기에는 어려움이 있어(Activity라는 Controller를 거치지 않을 수는 없기 때문에) 거의 사용하지 않는다.
장점
1. 간단하고 직관적이다.
2. 초기 개발 속도가 빠르다
단점
1. Controller가 비대해진다
2. Unit Test에 있어 어려움이 있다. -> View와 controller간의 결합도가 높아 테스트가 어려워진다.
3. View와 Model이 서로 의존하고 있고, 로직 단에서 UI단을 의존하게 되어 클린 아키텍처에 위배된다.
2. MVP
MVC 패턴에서 더 발전된 구조로, View와 Model 사이에 Presenter를 추가해 UI 로직과 비즈니스 로직을 더 명확하게 분리한 패턴이다. MVP의 경우 테스트 가능성 및 모듈화를 향상시키기 위해 널리 사용된다.
각 역할에 대해 알아보자면
Model
-> MVC와 동일하게 비즈니스 및 데이터 로직을 말한다.
View
-> UI를 담당하는 부분으로, Presenter에서 제공받은 데이터를 표시하고, 사용자 이벤트를 Presenter에 전달한다.
Presenter
-> View와 Model 사이의 중재자 역할을 한다.
-> View에서의 이벤트의 따라 Model에서 데이터를 가져오고, 해당 데이터를 가공해 View에 전달한다.
-> 모든 UI와 관련된 로직은 Presenter에서 처리되고, View는 단순히 UI의 업데이트만을 담당한다.
안드로이드에서 View의 경우는 Activity 및 layout 들이 담당하게 된다.
작동 흐름을 보자면, 다음과 같다.
1. View는 사용자의 입력을 받아 Presenter에 전달
2. Presenter는 Model에 데이터를 요청하거나 비즈니스 로직을 처리한다.
3. Model은 Presenter에 필요한 데이터를 반환하고, Presenter는 데이터를 가공해 View에 전달한다.
4. View는 Presenter로부터 받은 데이터를 화면에 표시한다.
장점
1. VIew와 Model이 서로 의존하지 않는다. -> MVC에서의 문제점
2. 로직이 각각 명확하게 분리되어 코드가 복잡해져도 유지보수가 수월하다.
단점
1. View와 Presenter가 1:1로 결합하고 있기 때문에 분리하기가 어려워진다.
2. 1:1 관계이기 때문에 View가 생기는 만큼 Presenter의 개수도 같이 늘어나게 된다.
코드로 보면 다음과 같다.
interface MainView{
fun showData(data : String)
}
class MainPresenter(private val view : MainView, private val model : MyModel){
fun onButtonClicked(){
val data = model.fetchData()
view.showData(data)
}
}
class MvpActivity : AppCompatActivity(), MainView {
private lateinit var presenter : MainPresenter
private lateinit var binding : ActivityMvpBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMvpBinding.inflate(layoutInflater)
setContentView(binding.root)
presenter = MainPresenter(this, MyModel())
binding.tvText.setOnClickListener{
presenter.onButtonClicked()
}
}
override fun showData(data: String) {
binding.tvText.text = data
}
}
class MyModel{
fun fetchData() : String{
return "데이터 업데이트"
}
}
3. MVVM
MVVM은 정말 널리 쓰이고 있는 아키텍처 패턴이다! 특히 Jetpack 라이브러리를 구글에서 제공함으로 훨씬 편하게 구현할 수 있다.
간단하게 얘기하자면, ViewModel은 View와 Model 사이에서 중개 역할을 하고, 데이터를 UI에 바인딩해 UI 업데이트를 자동으로 처리하는 구조이다.
MVVM의 구조는 다음과 같다.
Model
-> MVC, MVP와 동일하게 데이터를 관리하고 비즈니스 로직을 처리한다. ViewModel에 데이터를 전달하는 역할
View
-> UI 부분
-> 사용자의 입력을 ViewModel에 전달하고, ViewModel에서 제공하는 데이터를 관찰해 UI를 업데이트한다.
-> ViewModel을 참조하고 의존하고 있다.
ViewModel
-> Model에서 데이터를 가져와 View에 필요한 형태로 변환하고, LiveData 데이터 또는 StateFlow와 같이 관찰 가능한 데이터 홀더를 활용해 View에 데이터를 전달한다.
-> ViewModel은 View와 Model 간의 의존성을 최소화하고, 데이터 변경을 효율적으로 관리한다.
-> View에 대해 알지 못한다.
흐름을 보면 다음과 같다.
1. View는 사용자 입력을 ViewModel에 전달한다.
2. ViewModel은 Model에서 데이터를 요청한다.
3. Model은 데이터를 처리하고 ViewModel에 반환한다.
4. ViewModel은 LiveData를 활용해 View에 데이터를 전달하고, View는 얘를 관찰하며 UI를 업데이트한다.
장점
1. View가 Model에 의존하지 않고, ViewModel이 View에 의존하지 않는다.
2. 그렇기 떄문에 의존성 분리가 되고, View의 교체가 쉬워진다.
3. ViewModel과 View의 관계가 1:1이 아니여서, ViewModel을 여러 뷰에서 재활용할 수 있다.
단점
1. 데이터 바인딩과 같이 추가로 학습해야 하는 요소가 있다.
2. MVC, MVP에 비해 복잡한 코드
주의점
Jetpack의 AAC ViewModel과 차이점이 있다. MVVM에서의 ViewModel의 경우 아키텍처 관점에서의 ViewModel을 말하고, 실제 안드로이드 개발할 때 사용하는 ViewModel은 Jetpack의 ViewModel이다. 이 차이점을 명확하게 알고 있는 것이 중요하다 생각한다.
코드로 보면 다음과 같다.
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> get() = _data
fun fetchData() {
_data.value = "데이터 업데이트"
}
}
class MVVMActivity : AppCompatActivity() {
private lateinit var binding: ActivityMvvmactivityBinding
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMvvmactivityBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel.fetchData()
viewModel.data.observe(this) {
binding.tvText.text = it
}
}
}
이상 다음으로 MVI에 대해 학습하고 정리해보겠다.
참고자료
https://medium.com/delightroom/mvc-mvp-mvvm-mvi-아키텍쳐-안드로이드에서-이해하기-1-2442a4189c79
'Android > Android' 카테고리의 다른 글
[Android] LaunchMode (0) | 2024.10.31 |
---|---|
[Android] 아키텍처 - MVI (0) | 2024.10.28 |
[Android] 컴포넌트 - Service (8) | 2024.10.18 |
[Android] Gradle (0) | 2024.07.15 |
[Android] Jetpack이란? (0) | 2024.07.09 |