Mvx의 대원칙 (MVC)
MVC 플로우

MVC 요약정리본
여기서 의존성이란 내부에 해당 코드가 있는지 여부로 쉽게 이해 가능
Model
없음
Controller, View
Model은 순수 데이터 및 비즈니스 로직만 포함
View
Model
Controller
View는 Model의 데이터만 사용, Controller 직접 접근 금지
Controller
Model, View
없음
Controller는 Model과 View 모두 접근 가능
View가 Model로부터 데이터를 받을 때: 사용자마다 다르게 보여주는 데이터만 받아야 함.
View가 Model로부터 데이터를 받을 때: 반드시 Controller를 통해 받아야 함.
예제 코드 (Flutter/Dart 기반)
아래는 위 원칙을 적용한 간단한 예제입니다.
1. Model
class User {
final String name;
final int age;
User({required this.name, required this.age});
}
2. View
import 'package:flutter/material.dart';
class UserView extends StatelessWidget {
final String displayName;
const UserView({required this.displayName, super.key});
@override
Widget build(BuildContext context) {
return Text('안녕하세요, $displayName님!');
}
}
View는 오직 사용자에게 보여줄 데이터만 받음 (displayName).
3. Controller
class UserController {
final User user;
UserController(this.user);
// 사용자마다 다르게 보여줄 데이터만 가공
String getDisplayName() {
return '${user.name} (${user.age}세)';
}
}
4. 연결 예시 (Flutter 위젯 트리에서)
User user = User(name: '홍길동', age: 30);
UserController controller = UserController(user);
UserView(displayName: controller.getDisplayName());
View는 Controller를 통해 Model의 데이터를 받음.
View는 Controller와 직접적으로 의존하지 않고, 필요한 데이터만 생성자 파라미터로 받음.
Controller는 Model과 View 모두를 사용할 수 있음.
요약
Model: 데이터와 비즈니스 로직만 담당, View/Controller와 분리
View: 사용자에게 보여줄 데이터만 받고, Controller 직접 참조 금지
Controller: Model과 View 모두 접근 가능, View에 필요한 데이터를 가공해 전달
다만, 왜 Android 환경에서 MVC 패턴이 잘 적용되지 않는가

1. 모바일 환경의 문제
복잡한 비동기 처리 모바일 앱은 네트워크, 센서 등 다양한 비동기 작업이 많아, 단순한 MVC 구조로는 이런 이벤트를 깔끔하게 분리하기 어렵습니다.
라이프 사이클 처리 모바일 앱의 Activity/Fragment는 생명 주기(lifecycle)가 복잡해서, 뷰와 컨트롤러의 역할을 명확히 나누기가 어렵습니다.
UI 로직 분리의 어려움 웹의 HTML은 뷰와 컨트롤러가 완전히 분리되지만, 모바일은 뷰(UI)와 로직(Controller)이 자연스럽게 섞이기 쉽습니다.
예시
웹: 버튼 클릭 시 JS 컨트롤러에서만 로직 처리
모바일: 버튼 클릭 이벤트가 Activity/Fragment에 직접 구현됨
2. Android의 구조적 한계
뷰-컨트롤러 분리의 애매함
Android의 XML은 레이아웃(뷰)만 정의할 수 있고, UI 로직(컨트롤러)을 넣을 공간이 없습니다.
컨트롤러 역할을 Activity/Fragment가 담당해야 하는데, 이들이 뷰와 컨트롤러 역할을 동시에 하게 됩니다.
예시
// Activity가 뷰와 컨트롤러 역할을 모두 담당
class UserActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
// 뷰 초기화 + 버튼 클릭 이벤트 처리(컨트롤러 역할)
findViewById<Button>(R.id.button).setOnClickListener {
// 비즈니스 로직까지 여기서 처리
}
}
}
위 코드처럼 Activity에 UI 코드와 로직 코드가 섞여 있음
MVC의 Controller와 View가 명확히 분리되지 않음
3. 결과적 문제점
Fat Activity/Fragment Activity/Fragment에 로직이 집중되어 코드가 비대해짐 (유지보수, 테스트, 확장성 모두 저하)
테스트 어려움 대부분의 테스트 케이스에서 Android의
Context
가 필요해 유닛 테스트가 어렵고, 관심사의 분리가 무너짐
예시
Activity에서 직접 데이터 로딩, 화면 갱신, 네트워크 호출까지 처리
뷰와 로직이 섞여 테스트 코드 작성이 복잡해짐
안드로이드에서의 해결책


참고
Last updated