본문 바로가기

android studio

[Android] 디자인 패턴 비교 (MVC, MVP, MVVM, MVI)

디자인 패턴 비교 (MVC, MVP, MVVM, MVI)

패턴 View 중간 계층 Model 데이터 흐름 특징
MVC Activity/Fragement Controller 데이터 처리 View와 Controller가 직접
연결됨
안드로이드에서는
유지보수 어려움
MVP Activity/Fragement Presenter 데이터 처리 View는 Presenter를 통해
데이터 요청 및 UI 업데이트
테스트 용이,
코드 분리 가능
MVVM Activity/Fragement ViewModel 데이터 처리 ViewModel이 데이터 변경을 감지하고 자동 업데이트 LiveDate,StateFolw 활용 가능
MVI Activity/Fragement ViewModel
 + Reducer
데이터 처리 단방향 데이터 흐름
(UI → Intent → State)
UI 상태 관리가
강력함

 

1. MVC (Model-View-Controller)

초기 디자인 패턴으로 많이 사용되었지만, 안드로이드에서는 잘 사용되지 않음.
View와 Controller의 결합도가 높아서 유지보수가 어려운 단점이 있음.

 - 구조

  • Model: 데이터 및 비즈니스 로직 처리 (예: 데이터베이스, API)
  • View: 사용자 인터페이스 (예: Activity, Fragment, XML)
  • Controller: 사용자의 입력을 받아 Model을 업데이트하고 View를 갱신

 - 데이터 흐름

  1. 사용자가 버튼을 클릭 → Controller가 이벤트 처리
  2. Controller가 Model에서 데이터를 가져옴
  3. Model이 데이터를 반환 → Controller가 View를 업데이트

 - MVC 문제점

  • View와 Controller의 강한 결합: 유지보수가 어려움
  • Activity/Fragment가 Controller 역할을 하게 됨 → 코드가 복잡해짐

MVC 예제

class UserModel {
    fun getUserName(): String {
        return "고양이"
    }
}

class MainActivity : AppCompatActivity() {
    private val userModel = UserModel()

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

        button.setOnClickListener {
            textView.text = userModel.getUserName()
        }
    }
}

 

 

2. MVP (Model-View-Presenter)

MVC의 단점을 개선하여 Presenter를 도입한 패턴

  • View와 Model을 완전히 분리하여 코드 유지보수성을 높임
  • Presenter는 View와 Model의 중개 역할을 함
  • View는 Presenter만 호출하며, Model에 직접 접근하지 않음

 - 구조

  • Model: 데이터 처리 (예: DB, API)
  • View: UI 담당 (Activity, Fragment, XML)
  • Presenter: 비즈니스 로직을 담당하고 View와 Model을 연결

 - 데이터 흐름

  1. View가 Presenter에게 데이터 요청
  2. Presenter가 Model에서 데이터를 가져옴
  3. Presenter가 가공 후 View에 데이터 전달

 

MVP 예제

// Model
class UserModel {
    fun getUserName(): String {
        return "고양이"
    }
}

// View (Interface)
interface MainView {
    fun showUserName(name: String)
}

// Presenter
class MainPresenter(private val view: MainView) {
    private val model = UserModel()

    fun loadUser() {
        val userName = model.getUserName()
        view.showUserName(userName)
    }
}

// View (Activity)
class MainActivity : AppCompatActivity(), MainView {
    private lateinit var presenter: MainPresenter

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

        presenter = MainPresenter(this)

        button.setOnClickListener {
            presenter.loadUser()
        }
    }

    override fun showUserName(name: String) {
        textView.text = name
    }
}

 

3. MVVM (Model-View-ViewModel)

현재 안드로이드에서 가장 널리 사용되는 패턴

  • ViewModel이 LiveData 또는 StateFlow를 사용하여 UI 업데이트
  • View는 ViewModel만 관찰(Observe)하며, Model과 직접 연결되지 않음

MVVM 예제

class UserViewModel : ViewModel() {
    private val _userName = MutableLiveData<String>()
    val userName: LiveData<String> get() = _userName

    fun loadUser() {
        _userName.value = "고양이"
    }
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: UserViewModel

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

        viewModel = ViewModelProvider(this).get(UserViewModel::class.java)

        viewModel.userName.observe(this) { name ->
            textView.text = name
        }

        button.setOnClickListener {
            viewModel.loadUser()
        }
    }
}

 

 

4. MVI (Model-View-Intent)

MVVM을 확장하여 단방향 데이터 흐름을 강조한 패턴

  • View는 Intent를 ViewModel로 전달
  • ViewModel은 상태(State)를 생성하여 View에 전달
  • Redux 패턴과 유사하며, UI 상태 관리가 뛰어남

MVI 예제

sealed class MainIntent {
    object LoadUser : MainIntent()
}

data class MainState(val userName: String = "")

class MainViewModel : ViewModel() {
    private val _state = MutableLiveData<MainState>()
    val state: LiveData<MainState> get() = _state

    fun processIntent(intent: MainIntent) {
        when (intent) {
            is MainIntent.LoadUser -> _state.value = MainState(userName = "고양이")
        }
    }
}

class MainActivity : AppCompatActivity() {
    private lateinit var viewModel: MainViewModel

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

        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        viewModel.state.observe(this) { state ->
            textView.text = state.userName
        }

        button.setOnClickListener {
            viewModel.processIntent(MainIntent.LoadUser)
        }
    }
}

 

 

 디자인 패턴 선택

상황 추천 패턴
간단한 앱 MVVM (안드로이드 표준)
대규모 프로젝트 MVI (단방향 데이터 흐름)
기존 코드가 MVC MVP로 점진적 전환