2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
[Android] 디자인 패턴 이해 (MVC/MVP/MVVM)
1. 디자인 패턴이란?객체 지향 프로그래밍을 설계할 때 자주 발생하는 문제에 대응하기 위해서 사용되는 패턴을 의미한다.어떻게 보면 개발하는 방법을 공식화한 것이라고 생각하면 된다. 2.
goharry.tistory.com
2024.08.17 - [분류 전체보기] - [Android] MVP 패턴!
[Android] MVP 패턴!
디자인 패턴 관련 글들을 첨부하고 시작하겠습니다.2024.04.30 - [안드로이드] - [Android] 디자인 패턴 이해 (MVC/MVP/MVVM) [Android] 디자인 패턴 이해 (MVC/MVP/MVVM)1. 디자인 패턴이란?객체 지향 프로그래밍
goharry.tistory.com
많이 알려진 디자인패턴에 대해서 한번 정리를 했었다.
디자인패턴은 꽤나 중요한 개념이기 때문에 패턴 하나씩 다시 한번 정리를 해보려고 한다.
1. MVC 패턴이란?
위키피디아 에서는 다음과 같이 정의합니다.
모델-뷰-컨트롤러(model–view–controller, MVC)는 소프트웨어 공학에서 사용되는 소프트웨어 디자인 패턴
이다. 이 패턴을 성공적으로 사용하면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션
의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있다. MVC에서 모델은 애플리케이션의 정보(데이터)를 나타내며, 뷰는 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타내고, 컨트롤러는 데이터와 비즈니스 로직 사이의 상호동작을 관리한다.
내 마음대로 정리를 해보면, Model, View, Controller라는 개념으로 역할을 분리해서 개발을 하는 방법이라고 보면 될 것 같다.
2. Model, View, Controller의 동작
사용자가 Controller를 사용하게 되면 Controller는 Model에서 데이터를 받아오고, 받아 온 데이터를 통해 View에서 사용자에게 보이는 부분에 업데이트한다.
이 개념을 Android에서 사용한다고 생각하고 정리해 보자.
1. 사용자의 입력이 View를 통해 Controller로 들어온다.
2. Controller는 사용자의 입력을 받아 Model에 데이터 업데이트를 요청한다.
3. Model에서 데이터를 응답한다.
4. Controller는 Model에서 받은 데이터로 View에 업데이트를 요청한다.
5. View는 UI를 업데이트 한다.
(제가 틀리면 피드백 부탁드립니다.)
3. 구성요소 역할
1. Model(모델) - dataClass
역할
앱 내에서 필요한 데이터, 상태, 비즈니스 로직을 저장하고 처리한다.
2. View(뷰) - xml
역할
사용자가 직접 보는 UI를 담당
3. Controller(컨트롤러) - Activity/Fragment
역할
View와 Model 간의 관계를 설정하고, 앱의 로직을 담당
View와 Model의 데이터를 업데이트 하는 여할
다만, 안드로이드에서 View와 Controller를 묶어서 사실상 View라고 볼 수 있기 때문에 명시적으로는 이러한 역할이 드러나 보이지는 않는다.
4. MVC 패턴 장단점
1. 장점
- 앞의 그림과 같이 모델에서 데이터를 얻어서 뷰에 표현하고 이 모든 것을 컨트롤러가 중재하기 때문에 구조가 단순하고 직관적입니다. 그래서 MVC 패턴을 잘 모르는 사람이 있어도 쉽게 받아들이고 적용할 수 있습니다.
- 규모가 작은 애플리케이션에 MVC 패턴을 적용 시 개발기간이 짧아지고, 거의 모든 코드가 액티비티나 프래그먼트에서 작성되는 경향이 있어서 코드를 파악하기 쉽습니다.
2. 단점
- 액티비티 또는 프래그먼트가 뷰와 컨트롤러의 역할을 겸하는 구조라 코드량이 점진적으로 증가할 수밖에 없고, 그로 인해서 하나의 액티비티 또는 프래그먼트 클래스에서 수천 줄이 넘는 코드가 작성되기도 합니다. 그렇게 되면 스파게티 코드가 되고 유지보수 비용도 증가합니다.
- 컨트롤러는 뷰와 모델에 의존적이고, 뷰는 모델에 의존적이라 결합도가 높아 유닛 테스트가 거의 불가능합니다.
스파게티 코드(spaghetti code)는 컴퓨터 프로그램의 소스 코드가 복잡하게 얽힌 모습을 스파게티의 면발에 비유한 표현이다.
5. 예제
대단한 건 아니지만 간단한 예제를 한번 만들어 봤습니다.
예제를 만들어 보면서 좀 더 개념들이 명확해진 것 같네요.
다들 이론뿐만 아니라 실제로 적용해 보고 직접 만들어보는 것을 추천드립니다. 그래야 진짜 자기 것으로 만들 수 있는 것 같아요.
https://github.com/eukkbro/mvc
GitHub - eukkbro/mvc
Contribute to eukkbro/mvc development by creating an account on GitHub.
github.com
여기로 가시면 전체코드를 볼 수 있습니다.
간략 설명 : 구매할 아메리카노 개수를 증가, 감소 버튼을 통해 조절하고 전체 합계를 보여주는 앱 예제
1. View
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="131dp"
android:layout_marginTop="73dp"
android:layout_marginEnd="131dp"
android:text="아메리카노 한잔 : 1900원"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="95dp"
android:layout_marginEnd="280dp"
android:layout_marginBottom="317dp"
android:text="합계 : "
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/buttonSubtract"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="75dp"
android:layout_marginEnd="10dp"
android:text="-"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/buttonAdd"
app:layout_constraintEnd_toStartOf="@+id/textViewCount"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/buttonAdd" />
<Button
android:id="@+id/buttonAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="107dp"
android:layout_marginEnd="63dp"
android:layout_marginBottom="473dp"
android:text="+"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<TextView
android:id="@+id/textViewCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:text="0"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/buttonAdd"
app:layout_constraintEnd_toStartOf="@+id/buttonAdd"
app:layout_constraintStart_toEndOf="@+id/buttonSubtract"
app:layout_constraintTop_toTopOf="@+id/buttonAdd" />
<TextView
android:id="@+id/textViewTotalPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="147dp"
android:text="0원"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/textView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/textView2" />
</androidx.constraintlayout.widget.ConstraintLayout>
2. Controller
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val model = Model()
//뷰바인딩
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.buttonAdd.setOnClickListener {
model.add()
binding.textViewCount.text = model.total.toString()
binding.textViewTotalPrice.text = model.getTotalPrice().toString()+"원"
}
binding.buttonSubtract.setOnClickListener {
model.subtract()
binding.textViewCount.text = model.total.toString()
binding.textViewTotalPrice.text = model.getTotalPrice().toString()+"원"
}
}
}
3. Model
class Model {
private val americanoPrice = 1900
var total:Int = 0
fun add(){
total++
}
fun subtract(){
total--
}
fun getTotalPrice() : Int{
return total*americanoPrice
}
}
정리
Model을 보면 View와 연결된 부분이 전혀 없다. 그 외에도 의존성 없이 독립적이다. 대신 데이터를 가지며 데이터 변경이 가능한 함수로 구성되어 있다. 이렇게 데이터와 가공을 담당하고 있기 때문에 Controller에서는 해당 임무를 Model에 완전히 맡길 수 있고 맡겨야 한다.
그런데 아메리카노뿐만 아니라 다른 메뉴들까지 추가한다고 생각해 보면 Controller 부분에 View와 Model에 관련된 코드들이 굉장히 많이 늘어날 것이다. 이렇게 Controller에 코드가 쌓여서 비대해질 수가 있는 것이 MVC 패턴의 큰 단점이라고 볼 수 있다.
좀 더 제대로 정리를 해보긴 했지만 틀린 부분이 있을 수도 있다.
계속해서 배워가는 입장에서 언제든지 태클이나 질문은 환영입니다.
끝!
'안드로이드' 카테고리의 다른 글
[Android] Handler 예제 (2) | 2024.07.13 |
---|---|
[Android] 핸들러(Handler) (0) | 2024.05.09 |
[Android] 디자인 패턴 이해 (MVC/MVP/MVVM) (0) | 2024.04.30 |
[Android] SharedPreferences, 간단한 정보 저장/불러오기 (0) | 2024.04.30 |
[Android] AAC Room 사용해보기 (0) | 2024.04.25 |