📱 안드로이드 디자인 패턴: MVC부터 MVVM까지
🎯 목표
안드로이드 디자인 패턴(MVC, MVP, MVVM)을 이해하고 프로젝트에 적용하는 방법 학습
🧑🤝🧑 대상
- 안드로이드 프로젝트 생성 경험이 있는 개발자
- 안드로이드 디자인 패턴 적용에 어려움을 느끼는 개발자
🗺️ 목차
안드로이드 개발자를 위한 필수 디자인 패턴 핸드북 MVC, MVP, MVVM 완벽 가이드
-
안드로이드 디자인 패턴은 유지보수성과 확장성을 높이기 위해 코드의 역할을 분리하는 소프트웨어 설계 방식입니다.
-
MVC, MVP, MVVM은 안드로이드에서 주로 사용되는 대표적인 디자인 패턴으로, 각각 Model, View, Controller/Presenter/ViewModel의 역할을 명확히 나눕니다.
-
안드로이드 환경의 특성을 고려할 때, MVVM 패턴은 데이터 바인딩을 통해 View와 ViewModel의 의존성을 최소화하여 테스트 용이성과 코드 재사용성을 크게 향상시키는 가장 현대적인 접근법입니다.
1. 디자인 패턴 왜 필요한가? 잡동사니 방에서 정리된 서재로
새로운 안드로이드 프로젝트를 시작하고 코드를 작성하다 보면 어느새 하나의 파일에 모든 로직이 뒤섞여 버리는 경험을 하게 됩니다. 마치 잡동사니를 아무렇게나 쌓아둔 방처럼, 시간이 지날수록 어떤 코드가 어디에 있는지 찾기 어려워지고, 작은 기능 하나를 수정하거나 새로운 기능을 추가하는 것이 점점 더 힘들어집니다. 우리는 이러한 상태를 유지보수성이 떨어진다고 표현합니다.
소프트웨어 개발에서 디자인 패턴은 이러한 문제를 해결하기 위한 일종의 모범 사례입니다. 역할에 따라 코드를 논리적으로 분리하고 구조화하여, 시간이 지나도 코드를 쉽게 이해하고 수정하며 확장할 수 있도록 도와줍니다. 안드로이드 개발에서는 특히 UI와 비즈니스 로직을 분리하는 패턴들이 중요하게 사용됩니다. 이 핸드북은 안드로이드에서 가장 널리 사용되는 세 가지 디자인 패턴, 즉 MVC, MVP, MVVM에 대해 깊이 있게 탐구하고, 왜 이들이 필요하며 어떻게 발전해 왔는지 그 배경과 사용법을 상세하게 다룹니다.
2. MVC 패턴: 개념과 오해
2.1 MVC의 탄생 배경
MVC(Model-View-Controller)는 소프트웨어 디자인 패턴의 원조 격으로, 1970년대 후반 Smalltalk 언어 환경에서 처음 등장했습니다. 사용자 인터페이스를 담당하는 코드를 Model, View, Controller 세 가지 역할로 분리하여 효율적인 개발을 목표로 합니다.
-
Model: 데이터와 비즈니스 로직을 담당합니다. 데이터베이스, API 통신 등 앱의 핵심적인 데이터를 다루고, View나 Controller에 의존하지 않습니다.
-
View: 사용자에게 보여지는 UI를 담당합니다. 레이아웃(XML) 파일이나 위젯 등이 여기에 속합니다. 사용자의 입력을 받아 Controller에게 전달하는 역할도 수행합니다.
-
Controller: Model과 View의 중개자 역할을 합니다. View로부터 사용자 입력을 받아 Model을 업데이트하거나, Model의 변경 사항을 View에 반영하도록 지시합니다.
2.2 안드로이드에서의 MVC와 그 한계
안드로이드 개발을 처음 시작하면 누구나 MVC 패턴과 비슷한 구조를 접하게 됩니다. Activity는 Controller 역할을, Layout XML 파일은 View 역할을, 그리고 별도의 데이터 클래스는 Model 역할을 한다고 생각하기 쉽습니다.
하지만 안드로이드 환경에서 전통적인 MVC 패턴은 그대로 적용하기 어렵다는 큰 문제점이 있습니다. 안드로이드의 Activity는 단순한 Controller가 아니라 View의 역할까지 함께 수행하기 때문입니다. Activity는 레이아웃을 로딩하고, UI 이벤트를 처리하며, 심지어 Context라는 안드로이드 시스템의 핵심 자원을 가지고 있습니다. 즉, View와 Controller의 역할이 Activity라는 하나의 클래스에 강하게 결합되어 있는 형태입니다.
이러한 구조는 다음과 같은 문제점을 야기합니다.
-
Massive View/Controller:
Activity에 UI 로직과 비즈니스 로직이 뒤섞여 코드가 거대해집니다. -
유지보수성 저하:
Activity코드가 복잡해져서 새로운 기능을 추가하거나 버그를 수정하기가 어려워집니다. -
테스트의 어려움: UI와 비즈니스 로직이 분리되지 않아
JUnit과 같은 단위 테스트(Unit Test)를 수행하기가 매우 까다롭습니다.
이러한 안드로이드 고유의 문제점을 해결하기 위해 새로운 패턴이 필요하게 되었고, 그 대안으로 MVP 패턴이 등장하게 됩니다.
3. MVP 패턴: Controller를 Presenter로 대체하다
3.1 MVP의 개념과 등장 배경
MVP(Model-View-Presenter) 패턴은 MVC의 단점을 보완하기 위해 마이크로소프트에서 제시한 패턴입니다. MVC에서 Controller 역할을 하던 Activity가 View 역할을 겸하면서 발생했던 문제를 해결하기 위해, 순수하게 비즈니스 로직만 담당하는 **Presenter**를 새롭게 도입합니다.
-
Model: MVC와 동일하게 데이터와 비즈니스 로직을 담당.
-
View: 사용자 인터페이스를 담당하며, 오직 UI 렌더링과 사용자 입력 처리만 담당.
Activity나Fragment가 여기에 해당. -
Presenter:
View와Model의 중개자 역할을 합니다.View로부터 사용자 입력을 받고Model을 조작하며,Model의 변경 사항을View에게 전달하여 UI를 갱신하도록 요청합니다.View와Model은 서로를 직접적으로 알지 못하며,Presenter를 통해서만 소통합니다.
3.2 MVP 패턴의 동작 방식
MVP의 흐름은 다음과 같습니다.
-
사용자 입력: 사용자가 View(예: 버튼 클릭)를 조작합니다.
-
이벤트 전달: View는 사용자 입력을 감지하고, 이 이벤트를 Presenter에게 전달합니다.
-
데이터 조작: Presenter는 이벤트를 받아 Model의 데이터를 조작하거나 업데이트합니다.
-
UI 갱신 요청: Model의 데이터가 변경되면, Presenter는 View의 특정 메서드를 호출하여 UI를 갱신하도록 요청합니다.
3.3 MVP 패턴 적용하기
MVP를 안드로이드에 적용하는 가장 일반적인 방법은 Contract 인터페이스를 사용하는 것입니다.
-
Contract인터페이스 생성:View와Presenter가 서로 소통할 메서드들을 정의하는 인터페이스를 만듭니다. 이 인터페이스는 두 컴포넌트 간의 계약 역할을 합니다. -
View구현:Activity나Fragment가Contract.View인터페이스를 상속받아 UI 갱신 관련 메서드를 구현합니다. -
Presenter구현: 비즈니스 로직을 담은Presenter클래스를 만들고,Contract.Presenter인터페이스를 상속받아 사용자 입력 처리 관련 메서드를 구현합니다.
장점
-
역할 분리:
Activity의 역할을View와Presenter로 명확히 분리하여Activity가 UI 렌더링에만 집중하게 됩니다. -
테스트 용이성:
Presenter에 모든 비즈니스 로직이 담겨 있어, UI(View) 없이도Presenter에 대한 단위 테스트가 가능해집니다.
단점
-
강한 결합:
View와Presenter가 서로를 참조하며 강하게 결합되어 있어, 한쪽의 변경이 다른 쪽에 영향을 미칠 수 있습니다. -
보일러플레이트 코드:
Contract인터페이스에 모든 메서드를 정의해야 하므로, 기능이 많아질수록 코드가 불필요하게 길어지는 보일러플레이트 코드가 많이 발생합니다.
이러한 단점, 특히 View와 Presenter 간의 강한 결합을 해소하기 위해 등장한 것이 바로 MVVM 패턴입니다.
4. MVVM 패턴: 데이터 바인딩으로 결합을 약화시키다
4.1 MVVM의 개념과 등장 배경
MVVM(Model-View-ViewModel) 패턴은 MVP의 단점을 보완하기 위해 마이크로소프트의 WPF(Windows Presentation Foundation)에서 처음 소개되었습니다. Presenter의 역할을 하는 ViewModel을 도입하되, 데이터 바인딩이라는 기술을 활용하여 View와 ViewModel의 의존성을 완전히 분리하는 것이 핵심입니다.
-
Model: MVP와 동일하게 데이터와 비즈니스 로직을 담당.
-
View: 사용자 인터페이스를 담당하며,
ViewModel의 데이터를 관찰(Observe) 합니다.ViewModel의 변경 사항을 직접적으로 통지받는 대신, 데이터 바인딩을 통해 자동으로 UI가 갱신됩니다. -
ViewModel:
View를 위한 데이터를 가공하고,Model과의 상호작용을 담당합니다.View에 대한 참조를 전혀 가지지 않는다는 점이Presenter와의 가장 큰 차이점입니다.
4.2 MVVM 패턴의 동작 방식
MVVM의 핵심은 **데이터 바인딩(Data Binding)**과 **관찰 가능한 객체(Observable)**입니다.
-
사용자 입력: 사용자가 View를 조작합니다.
-
데이터 업데이트: View는 데이터 바인딩을 통해 ViewModel의 데이터를 직접적으로 업데이트합니다.
-
로직 처리: ViewModel은 업데이트된 데이터를 기반으로 Model의 데이터를 조작합니다.
-
UI 자동 갱신: Model의 데이터 변경 사항이 ViewModel에 반영되면,
LiveData나StateFlow같은 관찰 가능한 객체를 통해 변경 사항이 알림됩니다. View는 이 알림을 받고 자동으로 UI를 갱신합니다.
MVP와 달리, ViewModel은 View의 특정 메서드를 직접 호출하여 UI를 갱신할 필요가 없습니다. View는 그저 ViewModel의 데이터를 바라보고 있을 뿐이며, 데이터가 변경되면 스스로 UI를 업데이트합니다.
4.3 MVVM 패턴 적용하기
안드로이드에서 MVVM을 적용하기 위해서는 다음과 같은 기술들이 주로 사용됩니다.
-
AAC(Android Architecture Components): 구글에서 공식적으로 제공하는 라이브러리로, 특히 **
ViewModel**과 **LiveData**가 MVVM 구현에 핵심적인 역할을 합니다. -
Data Binding Library: XML 레이아웃 파일에서 직접
ViewModel의 데이터를 바인딩할 수 있도록 도와줍니다. -
Kotlin Coroutines & Flow: 비동기 작업을 효율적으로 처리하며, 데이터의 흐름을 관찰 가능한 형태로 제공합니다.
장점
-
낮은 결합도:
View와ViewModel이 서로의 존재를 모르므로 결합도가 매우 낮습니다. 이는 테스트 용이성을 극대화하고,ViewModel을 재사용하기 쉽게 만듭니다. -
테스트 용이성:
ViewModel은 안드로이드 프레임워크에 의존하지 않으므로, UI 없이도 비즈니스 로직에 대한 단위 테스트를 작성하기가 매우 쉽습니다. -
코드 재사용성: 하나의
ViewModel을 여러View에서 공유할 수 있어 코드 재사용성이 높아집니다.
단점
-
복잡도 증가: 데이터 바인딩,
LiveData,ViewModel등 여러 컴포넌트를 이해하고 사용해야 하므로, 초기 학습 곡선이 높고 프로젝트가 작을 경우 오버헤드가 발생할 수 있습니다. -
디버깅의 어려움: 데이터 바인딩으로 인해 UI가 어떻게 갱신되는지 명시적인 함수 호출로 파악하기 어려워 디버깅이 까다로울 수 있습니다.
5. MVC vs MVVM: 코드로 보는 차이점
간단한 카운터 앱을 예시로 들어 MVC와 MVVM 패턴의 코드를 비교해 보겠습니다.
5.1 MVC(Massive View-Controller) 패턴
Java
// Activity 클래스
class MainActivity : AppCompatActivity() {
private var count = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val countTextView = findViewById<TextView>(R.id.count_text_view)
val plusButton = findViewById<Button>(R.id.plus_button)
val minusButton = findViewById<Button>(R.id.minus_button)
countTextView.text = count.toString()
plusButton.setOnClickListener {
count++
countTextView.text = count.toString() // UI 직접 갱신
}
minusButton.setOnClickListener {
count--
countTextView.text = count.toString() // UI 직접 갱신
}
}
}
위 코드는 가장 기본적인 형태로, Activity가 데이터(count)와 UI(TextView, Button)를 모두 직접 다루고 있습니다. 이것이 안드로이드에서 흔히 볼 수 있는 Massive View-Controller의 전형적인 예시입니다. 비즈니스 로직(카운트 증가/감소)이 UI 로직(텍스트뷰 갱신)과 강하게 결합되어 있어, 테스트가 어렵고 코드가 복잡해질수록 유지보수가 힘들어집니다.
5.2 MVVM 패턴
Kotlin
// 1. ViewModel 클래스
class CounterViewModel : ViewModel() {
private val _count = MutableLiveData<Int>()
val count: LiveData<Int> = _count
init {
_count.value = 0
}
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
fun decrement() {
_count.value = (_count.value ?: 0) - 1
}
}
// 2. Activity 클래스 (View)
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this
binding.viewModel = viewModel // ViewModel 바인딩
// LiveData 관찰
viewModel.count.observe(this, Observer { newCount ->
binding.countTextView.text = newCount.toString()
})
}
}
-
ViewModel은 순수하게 데이터(_count)와 비즈니스 로직(increment(),decrement())만을 담당합니다.ViewModel은Activity나TextView같은View컴포넌트에 대해 전혀 모릅니다. -
Activity는viewModel의LiveData를observe하여 데이터 변경을 감지하고, 그에 따라 UI를 갱신합니다. -
XML 레이아웃 파일에 데이터 바인딩을 설정하면
Activity코드에서viewModel.count.observe코드조차 생략할 수 있습니다.ViewModel과View가 완전히 분리된 것을 볼 수 있습니다.
6. 결론: 가장 좋은 패턴은 없다, 가장 적합한 패턴만 있을 뿐
우리는 MVC, MVP, MVVM이라는 세 가지 안드로이드 디자인 패턴을 살펴보았습니다. 각각은 유지보수성과 확장성을 높이기 위해 코드의 역할을 분리한다는 공통된 목표를 가지고 있지만, 그 방법과 결과는 조금씩 다릅니다.
-
MVC: 개념적으로 간단하지만, 안드로이드 환경의 특성 때문에
Activity가View와Controller역할을 모두 떠맡아 코드가 비대해지는 문제가 발생합니다. -
MVP:
Activity에서 비즈니스 로직을 분리하기 위해Presenter를 도입하여 테스트 용이성을 크게 향상시켰습니다. 하지만View와Presenter간의 강한 결합과 보일러플레이트 코드가 단점으로 지적됩니다. -
MVVM: 데이터 바인딩과
LiveData같은 관찰 가능한 객체를 활용하여View와ViewModel의 의존성을 완전히 분리합니다. 이는 테스트 용이성과 코드 재사용성을 극대화하며, 현재 안드로이드 공식 문서에서도 권장하는 가장 현대적인 패턴입니다.
그렇다고 해서 MVVM이 항상 정답은 아닙니다. 매우 간단한 앱의 경우 MVP나 MVVM의 복잡도가 오히려 개발 속도를 늦출 수 있습니다.
중요한 것은 당신의 프로젝트 규모와 팀의 숙련도에 가장 적합한 패턴을 선택하는 것입니다. 디자인 패턴은 개발을 위한 도구일 뿐, 그 자체로 목표가 될 수는 없습니다. 이 핸드북을 통해 각 패턴의 장단점을 명확히 이해하고, 여러분의 프로젝트에 최적의 솔루션을 선택하는 데 도움이 되기를 바랍니다.
1. 🏛️ MVC (Model-View-Controller) 패턴
1.1. 🧩 구성 요소
- ==Model==: 데이터 관리
- ==View==: UI 표시
- ==Controller==: 사용자 입력 처리 및 Model과 View 연결
1.2. ⚠️ 문제점 (안드로이드)
- 액티비티가 Controller 역할 수행이 어려움 (View에 속함)
- 유지보수성 저하
1.3. 🧑💻 안드로이드에서의 MVC 패턴
graph LR A[User Input] --> B(Activity/View); B --> C(Model); C --> B;
2. 🧑💼 MVP (Model-View-Presenter) 패턴
2.1. 🔄 흐름
- User Input -> View
- View -> Presenter (이벤트 알림)
- Presenter -> Model (데이터 조작)
- Presenter -> View (결과 알림)
2.2. ➕ 특징
- Controller 대신 Presenter 사용
- View와 Model 간 의존성 제거
2.3. 🛠️ 적용 방법
- ==Contract 인터페이스 생성 (View, Presenter 인터페이스 포함)==
- Presenter 클래스 구현 (Contract.Presenter 상속)
- 액티비티 클래스 구현 (Contract.View 상속)
2.4. 💻 코드 예시 (토스트 메시지 앱)
interface Contract {
interface View {
void showToast(String message);
}
interface Presenter {
void buttonClick();
}
}2.5. 👍 장점
- 역할 분리 명확
- Model과 View 의존성 제거
2.6. 👎 단점
- View와 Presenter 강한 결합
- 테스트 어려움
- 보일러 플레이트 코드 증가
3. 🏗️ MVVM (Model-View-ViewModel) 패턴
3.1. 🤝 특징
- Presenter 대신 ViewModel 사용
- ==데이터 바인딩==을 통한 View와 ViewModel 간 결합 ==약화==
3.2. 🔄 흐름
- User Input -> View
- View -> ViewModel (이벤트 전달)
- ViewModel -> Model (데이터 조작)
- ViewModel -> View (데이터 바인딩, Observing)
3.3. 🛠️ 적용 방법
- 데이터 바인딩 활성화
- ViewModel 클래스 생성 (AAC ViewModel 상속)
- LiveData를 사용하여 데이터 변경 감지
- View에서 LiveData observe
3.4. 💻 코드 예시 (Count 객체 변화 감지)
// ViewModel
MutableLiveData<Integer> count = new MutableLiveData<>();
// View
count.observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
// UI 업데이트
}
});3.5. 👍 장점
- ViewModel이 View에 의존하지 않음
- 테스트 용이
- View 교체/ViewModel 재사용 가능 (Android 권장 X)
3.6. 👎 단점
- 복잡도 증가
- 양방향 데이터 바인딩 과다 사용 시 성능 저하 가능성
4. ⚖️ MVC vs MVVM 코드 비교 (예시: Count 앱)
4.1. 🔢 기능
- 1~10 사이 Count 객체
- "+" 버튼: 숫자 증가
- "-" 버튼: 숫자 감소
- "체크" 버튼: 랜덤 숫자와 비교 후 토스트 메시지 출력
4.2. 💻 코드 비교
- MVC: 액티비티에서 모든 로직 처리
- MVVM: ViewModel에서 로직 처리, View는 데이터 바인딩으로 UI 업데이트
4.3. 🖼️ 액티비티 코드 비교
- MVC
//...액티비티는 모든 로직을 처리합니다.- MVVM
//...액티비티에서는 데이터 바인딩과 ViewModel observer를 설정합니다.5. 🎯 결론
5.1. 🤔 MVVM 패턴이 항상 옳은가?
- ❌ 그렇지 않음
- 패턴은 패러다임이며, 프로젝트 특성과 개발자의 역량에 따라 선택해야 함
5.2. 💡 핵심
- 각 패턴의 특징을 이해하고 프로젝트에 맞는 최적의 패턴을 선택하는 것이 중요
대본
안녕하세요 우아한테크코스 6기 안드로이드 크루 악어입니다오늘은 안드로이드 MVC 부터 MVVM 패턴 까지 라는 주제로발표를 해보려고 합니다오늘 발표에 들어가기에 앞서서대상 청자는 안드로이드 프로젝트를 생성해본 경험이 있는 사람이면서동시에 안드로이드 디자인 패턴을 적용해보고 싶은데잘 모르는 사람이 대상이 될 것 같습니다목차는 다음과 같은데요MVC 패턴 그리고 MVP 패턴그리고 MVVM 패턴을 알아보려고 하고요시간이 된다면 코드로서MVC와 MVVM 패턴의 차이를 조금 알아보려고 합니다그리고 먼저 말씀드리자면이거는 패턴이 어떤 건지 알아보고 적용해 보는 것이 관건이고이 발표에서는 자세히 다루는 게 목적이 아니라는 점먼저 말씀드리고 시작하도록 하겠습니다그렇다면 MVC 패턴에 대해서 먼저 말을 해야 될 것 같은데요MVC 패턴은 모두가 잘 알다시피Model, View 그리고 Controller로 나누어지는 하나의 디자인 패턴입니다그리고 각각의 역할은 아래에 적혀 있는데요이것에 대한 자세한 설명은이미 데이터가 많이 있다 보니까아래에 있는 영상을 한번 참고해 보시면 좋을 것 같습니다그러면 왜 MVC 패턴을 적용했는가에 대해서먼저 질문을 가지고 들어가는 것이조금 더 바람직할 것 같습니다만약에 당신이 하나의 파일 안에서 코드를 계속 작성했다면왼쪽과 같은먼 훗날 당신이 코드를 되돌아 봤을 때당신의 파일은 이런 왼쪽의 모습과 비슷할 텐데요어떤 코드가 어디 있는지 찾기도 힘들고요어떻게 구조가 되어 있는지도 모르고요이것을 수정하는 그리고 변경하거나새로운 feature를 추가하는 것도 어려운 구조가 될 것입니다우리는 그것을 유지보수성이 떨어진다 라고 얘기를 하는데요그러한 것들을 개선하기 위해서각각의 역할에 따라서 나눈 모습이오른쪽의 모습처럼 나누었을 때그래서 나누었을 때 우리가 유지보수성이 올라가게 됩니다그 이유는 각각의 역할이 나눠져 있기 때문에어떤 코드가 어디 있는지 찾기도 쉽게 되고요수정이나 아니면 새로운 feature의 추가가 더 용이해지기 때문입니다우리는 한번 이제 가정을 해 보려고 합니다당신은 안드로이드 프로젝트를 새롭게 생성을 했습니다그리고 아주 간단한 앱을 만들기 위해서Model 클래스 하나를 넣어서 추가했다고 생각을 해 봅시다그러면 당신의 코드는당신의 안드로이드 프로젝트는이런 모습이 될 텐데요Controller로서 액티비티가 있고View로서 레이아웃 XML 파일이 있을 거고요그리고 당신이 만든 Model이 있을 겁니다축하합니다당신은 프로젝트를 생성만 했는데 MVC 패턴을 만드셨습니다너무 마음속으로 환호를 하고 있을지 모르겠지만사실 이것은 틀렸습니다MVC 패턴이 아니거든요사실 안드로이드에서는 안드로이드의 시스템 구조의 한계상Controller라고 불렀던 우리의 액티비티는Controller라고 부르기는 어렵고View에 속해 있습니다그렇기 때문에 사실 당신이 지금 만든 프로젝트는View와 Model로 이루어진 VM 패턴이라고 볼 수도 있겠는데요이것에 대해서 이해하기 좀 어려울 수 있어서예시로 하나 설명드리겠습니다당신이 만든 3인방Controller, Model, 그리고 View는이런 식으로 존재할 수 있을 것이라고 생각했겠지만사실 당신의 View는 이렇게 존재하고 있었기 때문입니다Controller의 로직을 잡아먹은 View가 되어버린 거죠자, 그랬을 때 우리가 앞서 말했던 것처럼역할이 제대로 분리되어 있지 않으면은이제 유지보수성이 떨어지게 되고어떤 문제들이 계속해서 발생하게 될 것입니다그랬을 때 우리는 MVP 패턴을 바라보게 됩니다MVP 패턴은 이제 기존에 있던 Controller의 위치에Presenter가 새롭게 들어오게 되고요흐름을 먼저 말씀을 드리면 User가 Input을 주었을 때View는 그 Input을 가지고이벤트를 Presenter에게 알려주게 됩니다Presenter는 자기가 가지고 있는 Model을 조작하고그 데이터 값을 가지고 필요하다면View에게 notify어떤 함수를 콜해서 View에게 알려줌으로써어떤 행위를 동작을 수행 요청을 하게 됩니다그렇다면 왜 Presenter가 새롭게 생겼는가 라고 했을 때사실상 Controller가 없었다고 보는 게 맞겠죠왜냐하면 기존에 Controller라고 불렀던 액티비티가View의 영역으로 옮겨지게 됐기 때문이죠그렇기 때문에 Controller의 역할을 하는Presenter를 새롭게 만들어주게 된 것입니다그렇다면 MVP 패턴을 어떻게 적용해 볼 수 있을까?이제 우리의 새로운 질문이 될 수 있을 것 같습니다첫 번째로는 Contract라고 하는 인터페이스를 만들게 될 건데요그 안에는 View와 Presenter라는 인터페이스를 담고 있는Contract 인터페이스를 만들게 될 겁니다그리고 두 번째로는 Presenter 클래스를 새롭게 만들 건데이 Presenter 클래스는Contract의 Presenter 인터페이스를 상속받을 거고요액티비티 클래스는 Contract의 View 인터페이스를 상속받게 될 겁니다한번 코드로 살펴보겠습니다이건 간단한 앱 예제를 만들어 본 건데요버튼을 클릭했을 때 토스트 메세지를 띄우는하나의 작은 앱을 MVP 패턴으로 만들었을 때이렇게 구현을 할 수 있을 것 같습니다그랬을 때 Contract 인터페이스를 만들고안에 있는 View와 Presenter의 행위를 설명하는 함수를 담고 있는인터페이스를 각각 만들 수 있을 거고요그러한 행위에 대한 구체적인 내용을안에서 상속을 받아서 구현을 하게 됩니다여기서 보시면 흐름은만약에 버튼 클릭 리스너가 호출되게 됐을 때Presenter에게 이벤트를 알려주게 되죠Presenter한테 버튼이 클릭됐다라는 이벤트를 알려주게 되고Presenter에서는 여기서는 존재하지 않지만필요하다면 어떤 Model의 변경이나 조작을 하고View에게 토스트 메세지를 보내달라는 필요한 요청을이제 notify 함으로써 알려주게 됩니다그래서 이런 식으로 상호작용을 하게 되는 거죠그러면 MVP 패턴의 장점과 단점을 비교해 볼 수 있을 것 같은데요일단은 역할에 대한 분리가 잘 이루어졌고요그리고 Model과 View의 의존성이 지금은 지워졌다는 걸 알 수 있습니다하지만 단점으로는 View와 Presenter가강하게 결합되어 있다는 것을 알 수 있습니다그렇기 때문에 강하게 결합되어 있다는 것은테스트를 하기 어렵다는 구조도 알 수 있을 거고요그리고 이러한 관계를 유지하기 위해서보일러 플레이트 코드가 발생하게 되는데앞서 말씀드렸던 것처럼Contract 계약서라는 계약서의 이름이죠계약서가 계속해서 동작이 많아지면 많아질수록계약서가 더 길어질 겁니다그렇기 때문에 보일러 플레이트 코드계속 불필요하다기보다는의미 없는 코드들이 계속해서 늘어나게 될 거고그런 것들은 상당히 단점으로 다가오게 될 것입니다이러한 시점에서 우리는 MVVM 패턴을 바라보게 될 것입니다MVVM 패턴은 MVP 패턴과 상당히 유사한 모습을 보여주고 있고Presenter 위치에 ViewModel로 변경된 것 아닌가라는 생각이 들 수 있는데요일부는 맞고 일부는 틀립니다ViewModel로 대체는 되었으나한 가지 더 다른 점은 아래에 있는 화살표가실선에서 점선으로 변경되었죠이 내용은 기존에 강하게 결합되어 있던 것이이제는 결합이 지워졌거나 결합이 약해졌다고 볼 수 있습니다이 내용은 데이터 바인딩을 사용했기 때문에 가능한 내용인데요그렇기 때문에 더 이제 흐름을 봤을 때는기존에는 View가 ViewModel을 알고 있고ViewModel도 View를 알고 있었다ViewModel이 아니죠Presenter가 View를 알고 있고View도 Presenter를 알고 있는 그런 구조였는데이제는 더 이상 ViewModel이 View를 몰라도 되는 구조가 이제 된 것입니다User가 Input을 줬을 때 이벤트를 쏘고Manipulate이제 ViewModel은 Model을 조작하고이런 변화를 자체적으로 데이터 값으로 가지고 있겠죠그러한 변화에 대해서View는 데이터 바인딩을 통해서 Observing을 하고 있기 때문에직접적으로 함수로 콜을 하지 않아도 View는 알게 되고이제 이러한 구조가 서로의 의존성이 없더라도기존의 구조를 잘 지킬 수 있게 되는 겁니다그렇다면 어떻게 적용해 볼 수 있을까 가또 새로운 관건이 될 것입니다이 네 가지 단계를 사용하면 쉽게 구현을 할 수 있을 텐데요첫 번째로는 데이터 바인딩을 가능하게 해주고그리고 ViewModel이 AAC ViewModel을 상속받게 해줍니다이것은 간단하게 하기 위해서 한 내용이고요그리고 LiveData를 통해서내가 변화를 감지하고자 하는 내용을LiveData로 만들어주고요그리고 View에서는 이러한 LiveData로 만든 것을 observe,관찰할 수 있게 해준다면이러한 것들을 적용을 할 수 있게 됩니다자 그러면 코드로 봤을 때는 이런 식으로 구현이 될 거고요Count라는 객체를 새롭게 만들었을 때이제 이것에 대해서 변화를 감지하고 싶어 라고 한다면이런 식으로 적고이제 액티비티에서는 이제 View에서죠View에서는 observe맨 아래에 있는 함수인데 이 observe를 통해서이것에 대한 Count 객체에 대해서 변화를 감지하게 되고그것을 통해서 이제 View까지 계속 변경을 쉽게서로 알지 못하지만 View를 변경할 수 있게 할 수 있습니다이것에 대해 MVVM 패턴에 대해서도장단점을 비교해 보면 좋을 것 같은데요장점은 ViewModel이 더 이상 View에 의존하지 않고 있습니다그렇기 때문에 의존하지 않고 있다는 것은테스트가 용이하다는 것을 알 수 있고요의존하고 있지 않기 때문에또 동시에 View를 교체하거나아니면 ViewModel을 재사용할 수도 있습니다단지 안드로이드에서는ViewModel의 재사용을 권장하고 있지 않다는 점을먼저 말씀드립니다그리고 단점으로는 복잡도가 증가하게 되고요만약 양방향 데이터 바인딩을 많이 사용하고 있거나아니면 프로젝트가 충분히 큰 규모라는 지점에서는성능이 저하될 수 있는 여지가 있습니다이거는 MVC 패턴과 MVVM 패턴으로제가 만든 예제를 두 개 다 구현을 해본 건데요1에서 10 사이의 숫자로 움직이는 Count 객체를 만들고플러스 버튼을 누르면 숫자가 늘어나고마이너스 버튼을 누르면 숫자가 내려갑니다그리고 체크 버튼을 누르면초기에 랜덤하게 만들어진 숫자와 맞는지를 비교해 주는토스트 메세지를 띄워줍니다그거를 MVC 우리가 기존에 만들었던 패턴대로 만든다면이런 식으로 작성이 될 거고요MVVM 패턴으로 만든다면 ViewModel이 이런 식으로 작성이 되게 되고View인 액티비티 코드는 이런 식으로 바뀌게 될 것입니다앞에 있는 Model은 똑같이 사용할 거고요다만 데이터 바인딩을 사용하려면XML 코드가 좀 변경이 필요한데이 내용은 여기에 담겨 있지 않다는 점 먼저 말씀드립니다자 긴 여정 드디어 끝나가는데요우리는 이제 MVC, MVP, MVVM 패턴을어떻게 적용할 수 있는가를 배워 보았습니다그러면 결론적으로는 MVVM 패턴이 가장 큰 장점을 가지고 있는 건데그러면 MVVM 패턴이 항상 옳은가요?라는 질문에 있었을 때 그렇지 않습니다패턴은 언제나 하나의 패러다임이고당신과 당신의 프로젝트에 의존하고 있기 때문에당신이 잘 선택해서 취사 선택하시면 될 것 같습니다여기까지 우아한테크코스 6기 안드로이드 크루 악어였습니다감사합니다