안녕하세요!
이번 글에서는 MVP(Model-View-Presenter) 패턴에 대해 자세히 알아보겠습니다.
MVC 패턴과 마찬가지로 MVP 패턴도 애플리케이션의 구조를 명확히 하고, 유지 보수성을 높이기 위해 사용됩니다.
이제 MVP 패턴의 개념, MVC 패턴과 비교해서 어떤 점이 보완되었는지,
MVP 패턴의 이해, MVP 패턴의 장단점까지 살펴보겠습니다.
MVP 패턴이란?
MVP 패턴은 Model, View, Presenter 세 가지 구성 요소를 가지는 디자인 패턴입니다.
각 구성 요소는 특정한 역할을 담당하고 서로 독립적으로 동작할 수 있도록 설계되었습니다.
1. 뷰 : View
사용자 인터페이스를 담당합니다.
사용자 입력을 받아 프리젠터에게 전달하고, 프리젠터로부터 받은 데이터를 화면에 표시합니다.
2. 모델 : Model
데이터를 관리하고 관련 비즈니스 로직을 처리합니다.
3. 프리젠터 : Presenter
뷰와 모델을 연결하는 중간 관리자 역할을 합니다.
사용자의 이벤트를 받아서 처리하고 모델을 업데이트하며 뷰를 갱신합니다.
MVC 패턴 vs MVP 패턴
MVC 패턴에서 Activity 또는 Fragment가 컨트롤러 역할을 합니다.
엄밀히 말하면 화면 컴포넌트인 Activity 또는 Fragment가 사용자 입력 처리, 비즈니스 로직, 화면 업데이트를 모두 관리하는 겁니다. 이렇게 뷰이면서 동시에 컨트롤러 역할을 수행하기 때문에 역할 분리가 명확하지 않고, 컨트롤러의 복잡성 증가와 재사용성 부족이라는 한계점이 있습니다. (MVC 패턴 자세히 보기)
MVP 패턴은 MVC 패턴의 단점을 보완하기 위해 등장했습니다.
MVP 패턴에서는 Activity 또는 Fragment가 뷰 역할을 하고 프리젠터가 새로 등장합니다.
Activity 또는 Fragment는 단순히 프리젠터로부터 받은 데이터를 화면에 표시하는 역할을 하며, 모든 비즈니스 로직은 프리젠터에서 처리합니다. 이로 인해 역할은 좀 더 명확하게 분리되고 뷰와 모델 간의 결합도는 낮아집니다.
MVP 패턴 이해 (+예제)
간단한 예제를 통해 MVP 패턴을 좀 더 이해할 수 있습니다.
MainAvtivity, MainPresenter, MainModel 각각 어떤 역할을 하는지 살펴보도록 하겠습니다.
1. 뷰 : MainActivity
사용자 입력을 받아 프리젠터에게 전달을 하고, 프리젠터로부터 전달받은 정보를 화면 업데이트 합니다.
class MainActivity : AppCompatActivity(), MainContract.View {
private lateinit var binding: ActivityMainBinding
private val mainModel = MainModel("A", 1)
private val mainPresenter = MainPresenter(this, mainModel)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.btnUpdate.setOnClickListener {
mainPresenter.update("B", 2) // 프리젠터 상호작용
}
binding.btnReset.setOnClickListener {
mainPresenter.reset() // 프리젠터 상호작용
}
}
override fun updateView(model: MainModel) {
binding.tvResult.text = "$model"
}
}
2. 모델 : MainModel
데이터 관리 및 데이터 관련 비즈니스 로직을 처리합니다.
data class MainModel(var name: String, var value: Int) {
// 데이터 관리 : MainModel(name, value)
// 데이터 관련 비즈니스 로직 처리 : update, reset
fun update(name: String, value: Int) {
this.name = name
this.value = value
}
fun reset() {
this.name = ""
this.value = 0
}
}
3. 프리젠터 : MainPresenter
뷰와 모델을 연결하는 중간관리자 역할을 합니다.
프리젠터는 뷰와 모델 사이에서 비즈니스 로직을 수행하며 이벤트와 데이터를 주고받습니다.
Constract 인터페이스는 뷰와 프리젠터의 상호작용을 명확하게 분리해서 코드의 가독성을 높일 수 있습니다.
interface MainContract {
interface View {
fun updateView(model: MainModel)
}
interface Presenter {
fun update(name: String, value: Int)
fun reset()
}
}
class MainPresenter(private val view: MainContract.View, private val model: MainModel): MainContract.Presenter {
override fun update(name: String, value: Int) {
model.update(name, value) // 모델 설정
view.updateView(model) // 뷰 업데이트
}
override fun reset() {
model.reset() // 모델 설정
view.updateView(model) // 뷰 업데이트
}
}
MVP 패턴 장단점
MVP 패턴 장점
- UI 로직과 비즈니스 로직을 명확하게 분리된다.
- 프리젠터를 통해서 뷰와 모델 간에 결합도를 낮춘다.
MVP 패턴 단점
- 뷰와 프리젠터를 분리하는 작업으로 코드의 양이 증가한다.
- 뷰와 모델 간에 결합도는 낮췄지만, 뷰와 프리젠터간에 결합도가 높다.
결론
MVP 패턴은 MVC 패턴의 단점을 보완하여 뷰와 비즈니스 로직을 명확하게 분리하고 유지보수성과 테스트 용이성을 높였습니다. 그러나 MVP 패턴에서 뷰와 모델 간에 강한 결합을 낮췄지만 뷰와 프리젠터간에 강한 결합을 가지게 됩니다. 다음 글에서는 이러한 한계를 극복한 MVVM(Model-View-ViewModel) 패턴에 대해 정리할 예정입니다.
관련 글
참고자료
Simple Android MVP Pattern Implementation
'안드로이드 > 디자인 패턴' 카테고리의 다른 글
코틀린 싱글톤 패턴: 어떤 방법이 좋을까? (0) | 2024.06.13 |
---|---|
안드로이드 디자인 패턴: MVVM 완벽 정리 (0) | 2024.05.27 |
안드로이드 디자인 패턴: MVC 패턴 완벽 정리 (0) | 2024.05.24 |
댓글