디자인 패턴 관련 글들을 첨부하고 시작하겠습니다.
2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
[Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
1. 디자인 패턴이란?객체 지향 프로그래밍을 설계할 때 자주 발생하는 문제에 대응하기 위해서 사용되는 패턴을 의미한다.어떻게 보면 개발하는 방법을 공식화한 것이라고 생각하면 된다. 2.
goharry.tistory.com
2024.05.04 - [안드로이드] - [Android] MVC 패턴!
[Android] MVC 패턴!
2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM) [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)1. 디자인 패턴이란?객체 지향 프로그래밍을 설계할 때 자주 발생하는 문제에 대응하기 위해서
goharry.tistory.com
1. MVP 패턴이란?
위키피디아에서는 다음과 같이 정의합니다.
모델-뷰-프리젠터(model-view-presenter, MVP)는 모델-뷰-컨트롤러(MVC) 아키텍처 패턴의 파생 패턴으로, 사용자 인터페이스를 개발하기 위해 대부분 사용된다.
MVP에서 프리젠터는 "middle-man"의 기능을 담당한다. MVP에서는 모든 프레젠테이션 로직은 프리젠터로 넘어간다.
2. Model, View, Presenter의 동작
- 사용자의 입력이 View를 통해 Presenter로 들어온다.
- Presenter는 사용자의 입력을 받아 Model에게 데이터를 요청한다.
- Model은 요청받은 데이터를 Presenter에 응답한다.
- Presenter가 Model로부터 받은 데이터를 처리하여 View에 보낸다.
- View는 UI를 업데이트 한다.
3. 구성요소의 역할
1. Model(모델)
앱 내에서 필요한 데이터, 상태, 비즈니스 로직을 저장하고 처리하는 역할
2. View(뷰)
사용자가 직접 보는 UI를 담당
3. Presenter(프레젠터)
View와 Model 사이에서 데이터를 처리하고 전달하는 역할, Interface 형식으로 되어 있어 View와 독립적이다.
4. MVP 패턴의 장단점
장점
View와 Model의 의존성이 없다. (MVC 패턴의 단점이었던 View와 Model 사이의 의존성을 해결)
View와 Presenter를 분리하여 테스트 용이성을 높인다.
단점
View와 Presenter 사이의 높은 의존성을 갖게 된다.
복잡해질수록 의존성이 강해진다.
5. 예제
전체코드
https://github.com/eukkbro/designPattern
GitHub - eukkbro/designPattern
Contribute to eukkbro/designPattern development by creating an account on GitHub.
github.com
예제 간단 설명
바텀내비게이션으로 각각의 프래그먼트를 mvc, mvp, mvvm 패턴으로 동작하게 만들었습니다.
버튼을 클릭하면 랜덤 한 고양이 사진이 나오는 예제입니다.
따라서, MVP 패턴 관련 부분만 작성하겠습니다.
1. View(MVPFragment)
먼저 View입니다.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".mvp.MvpFragment"
android:padding="20dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:scaleType="fitCenter"
android:src="@drawable/ic_launcher_background" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="@string/another"
style="@style/button_normal"
/>
</LinearLayout>
</layout>
Mvp Fragment에서 Presenter.View를 상속하고 있습니다.
편한 구현을 위해서 데이터 바인딩을 사용했습니다.
class MvpFragment : Fragment(), Presenter.View{
private val TAG = "mvp 프래그먼트"
private lateinit var binding: FragmentMvpBinding
private lateinit var presenterImpl: PresenterImpl
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
/**데이터 바인딩**/
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_mvp, container, false)
/**초기화**/
setInitialize()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
/**리스너 설정**/
setListener()
}
private fun setInitialize(){
/**프레젠터 불러오기**/
presenterImpl = PresenterImpl(this)
}
private fun setListener(){
/**버튼 클릭 리스너**/
binding.button.setOnClickListener {
Log.d(TAG, "View에서 받은 사용자의 입력을 받는다.")
Log.d(TAG, "View에서 Presenter에게 데이터를 요청")
presenterImpl.getCatUrl()
}
}
override fun setImageView(url: String) {
/**글라이드**/
Glide.with(this)
.load(url)
.placeholder(R.drawable.loading)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(binding.imageView)
}
}
2. Presenter
인터페이스 형태인 프레젠터입니다.
interface Presenter {
fun getCatUrl()
interface View{
fun setImageView(url: String)
}
}
그리고 그 프레젠터의 실제 구현부라고 볼 수 있습니다.
class PresenterImpl(private val view: Presenter.View): Presenter {
private val TAG = "mvp 프레젠터 구현부"
private val model: Model
get() = Model()
override fun getCatUrl() {
Log.d(TAG, "Presenter는 Model에게 데이터를 요청")
view.setImageView(model.getCatUrl())
Log.d(TAG, "Presenter가 모델로부터 받은 데이터를 처리해서 뷰에 전달")
}
}
3. Model
요청받은 데이터를 가공하고 응답하는 부분입니다.
여기서는 randomCatUrl을 반환하고 있습니다.
class Model {
private val TAG = "mvp 모델"
private var randomCatUrl = "https://cataas.com/cat?type=square"
fun getCatUrl(): String{
Log.d(TAG, "요청받은 데이터를 전달")
return randomCatUrl
}
}
정리
인터페이스를 많이 사용해보지 않아서 낯선감이 좀 들긴 했었다.
MVC 패턴의 단점이었던 Model과 Controller의 강한 의존성을 이렇게 인터페이스를 사용해서 분리를 한 게 신기했다.
최근에 솔리드 원칙이라던지 추상화 등등 인터페이스 관련해서 공부를 자주 하게 되는 것 같은데
비슷한 맥락인 것 같다.
근데 오히려 MVVM을 먼저 구현해 본 것도 있고 인터페이스를 활용을 잘 못하고 있어서 그런지 개인적으로 MVP 패턴을 구성하는 것이 MVVM 패턴을 구성하는 것보다 좀 더 복잡하다는 느낌이 들었다.
인터페이스와 인터페이스 구현부까지 만들어야 된다고 생각하니 조금 머리가 아픈 것 같기도.
끝!
'안드로이드' 카테고리의 다른 글
[Android] 기본 스플래시 없애기 (0) | 2024.08.21 |
---|---|
[Android] MVVM 패턴 예제! (1) | 2024.08.18 |
[Android] Glide 3 - 원형 이미지에 로딩 애니메이션 구현 (4) | 2024.07.29 |
[Android] Glide 2 - 로딩 애니메이션 구현 (0) | 2024.07.27 |
[Android] Handler 예제 (2) | 2024.07.13 |