Beeeam

Android MVC 패턴 본문

Android

Android MVC 패턴

Beamjun 2023. 3. 9. 20:55

사실 안드로이드 관련 자료를 찾아보거나 회사 기술 스택들을 보면서 MVVM을 많이 보았는데 이때는 그냥 많이 사용되는 개념이구나 하고 넘겼었다. 근데 이번에 동아리 발표를 준비하면서 주제를 뭘로 할까 생각하다가 안드로이드에서 많이 사용되고, 안드로이드가 아닌 sw 개발에서도 많이 사용되는 MVVM에 대해서 발표를 하면 좋을 것 같다는 생각이 들었고, MVVM을 공부하는 김에 안드로이드에서 사용되는 여러 디자인 패턴들을 공부하고, 발표 해야 겠다는 생각이 들었다.

 

먼저 앞에서 언급한 것 처럼 MVC, MVP, MVVM 모두 디자인 패턴인데 디자인 패턴이 무엇인지, 왜 사용하는지를 알아야 할 것 같다.

디자인 패턴?

소프트웨어 디자인 패턴(software design pattern)은 소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다. 소스나 기계 코드로 바로 전환될 수 있는 완성된 디자인은 아니며, 다른 상황에 맞게 사용될 수 있는 문제들을 해결하는데에 쓰이는 서술이나 템플릿이다. 디자인 패턴은 프로그래머가 어플리케이션이나 시스템을 디자인할 때 공통된 문제들을 해결하는데에 쓰이는 형식화 된 가장 좋은 관행이다.

 

 

위키백과에서 디자인 패턴에 대해서 설명하고 있는 글이다.

본인은 디자인 패턴을 공통적인 문제를 해결하는 해결책으로 이해하였고, 이러한 개념은 여러 개발자들이 공통된 문제를 겪고, 이를 해결하기 위해서 형식화된 구조로 SW를 설계하면서 생겨난 것 같다.

위 글을 읽으면서  “사용하면 좋구나” 라는 생각이 들었다. 먼저 디자인 패턴을 사용하게 되면 코드를 역할에 따라서 분류하기 때문에 코드가 깔끔해지는데 이로 인해 코드의 유지 보수가 편해진다.

본인은 작은 프로젝트만 진행을 해봐서 필요성을 크게 느낀 적은 없긴 했는데 최근에 예전 코드를 다시 볼 일이 있어서 봤는데 엄청 지저분하게 느껴졌다. 그래서 좀 보기가 힘들었다;; 이 때 디자인 패턴의 필요성을 좀 느꼈던 것 같다.

여튼 이제 디자인 패턴이 무엇인지, 왜 사용해야 하는지 알았으니 이제 본격적으로 주제에 대해서 알아보자!

 

MVC

Model View Controller의 약자인 MVC는 안드로이드와 관계 없이 sw 개발에서 가장 널리 사용되는 디자인 패턴이다. (사실 안드로이드에서는 이제 잘 사용하지 않음)

약자 그대로 Model, View, Controller로 구성이 된다. 입력은 모두 Controller에서 발생하고, 관리하는 구조이다.

MVC의 흐름을 표현 해봤다. 흐름을 보면 먼저 usercontroller에게 어떤 요청을 하면 controllermodel데이터를 요청하고 model은 controller를 통해서 데이터view에 보내고 view는 이 데이터를 user에게 보여준다.

 

각 요소가 어떤 역할을 하는지 보자.

 

Model

  • 앱에서 사용되는 데이터를 가지고, 그 데이터를 처리하는 역할
    데이터와 관련

View

  • 사용자에게 보여지는 화면
  • 사용자의 입력에 대해서 어떤 동작을 해야하는지는 몰라야함
    사용자에게 보여지는 부분

Controller

  • View와 Model의 중재자 역할
  • View를 통해서 사용자의 입력을 전달 받고, 이를 적절하게 처리하는 역할
    Model과 View를 이어주는 부분

MVC 패턴의 규칙

  1. Model은 Controller와 View에 의존하지 않는다.
    (Model 내부에 Controller와 View 관련 코드 있으면 X)
  2. View는 Model에만 의존해야 하고, Controller에는 의존하면 안된다.
    (View 내부에는 Model의 코드만 있어도 OK, Controller의 코드는 있으면 X)
  3. View는 사용자 마다 다르게 보여줘야 하는 데이터만 Model에서 받아온다.
  4. Controller는 Model과 View에 의존해도 된다.
    (Controller 안에는 Model, View 코드 있어도 OK)
  5. View가 Model로 부터 데이터를 받아올 때는 반드시 Controller를 통해서 받아와야 한다.

 

안드로이드에서의 MVC

안드로이드에서는 activity / fragment 가 View와 Controller 역할을 하기 때문에 위와 같은 순서로 동작한다.

 

장점

  1. 앱에서 기능 구현을 하기 쉽다.
  2. Activity / Fragment 파일에서 모든 동작을 선언하면 되서 개발 기간이 단축된다.
  3. 작은 앱에서는 코드 분석이 쉽다.

단점

  1. 하나의 클래스(Controller)에 코드의 양이 증가한다.
  2. 스파게티 코드가 될 가능성이 높아서 유지 보수가 어려워진다.
  3. View와 Model간의 의존성이 높아진다.

 

MVC 적용 예시

밑의 코드는 사용자로부터 간단한 로그인 기능을 가진 앱을 구현한 것이다. 이미 저장되어 있는 아이디, 비밀번호와 비교하여 로그인 성공 여부를 알려준다.

아주 간단한 코드지만 MVC 방식의 동작 흐름을 보기 위해서 만들었다.

Model (Data.kt)

data class Data(
    var usrName: String? = null,
    var password: String? = null
) {
    fun login(usrName: String?, password: String?): Boolean {
        return usrName == "abc" && password == "1234"
    }
}

Model에서 로그인의 성공 여부를 판단한다. (데이터 관련 처리)

View (activity_main.xml)

<?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=".controller.MainActivity">

    <EditText
        android:id="@+id/edt_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:hint="아이디"
        app:layout_constraintBottom_toTopOf="@+id/edt_password"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_goneMarginBottom="10dp" />

    <EditText
        android:id="@+id/edt_password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:hint="비밀 번호"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="로그인"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/edt_password" />

    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_login"
        tools:text="성공!" />


</androidx.constraintlayout.widget.ConstraintLayout>

View에서는 데이터를 화면에 출력한다.

View / Controller (MainActivity.kt)

class MainActivity : AppCompatActivity() {

    private lateinit var data: Data

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val edtId = findViewById<EditText>(R.id.edt_id)
        val edtPassword = findViewById<EditText>(R.id.edt_password)
        val btnLogin = findViewById<Button>(R.id.btn_login)
        val tvResult = findViewById<TextView>(R.id.tv_result)

        data = Data()

        btnLogin.setOnClickListener {
            val loginStatus = data.login(
                edtId.text.toString(),
                edtPassword.text.toString()
            )

            if (loginStatus) {
                tvResult.text = "성공!"
            } else {
                tvResult.text = "실패.."
            }
        }
    }
}

Activity 에서는 사용자의 이벤트에 따라 Mode로 부터 로그인 성공 여부를 받아와서 이에 따라 처리한다.

(View와 Model의 중재자 역할)

 

 

GitHub - BeamjunCho9/Android_MVC_example

Contribute to BeamjunCho9/Android_MVC_example development by creating an account on GitHub.

github.com

 

정리

MVC 패턴은 디자인 패턴 중에서 가장 간단한 것 같다. 모든 동작들을 Activity나 Fragment에 선언하면 되기 때문에 기능이 적은 앱을 만들 때 적용하면 효율적인 것 같다(너무 간단해서 디자인 패턴을 적용했다고 말하기도 좀 그런거 같다;;). 하지만 기능이 많은 앱을 만들 때는 코드들이 복잡하게 얽히는 문제가 생길 가능성이 높아서 적합하지 않은 디자인 패턴인 것 같다.