MVVM(Model-View-ViewModel) 란?
- UI 애플리케이션에서 사용되는 디자인 패턴(사용자가 프로그램과 상호작용할 수 있도록 설계된 애플리케이션)
- 사용자 인터페이스(UI)와 애플리케이션의 비즈니스 로직을 분리하여 유지보수성과 테스트 용이성을 향상
- Angular, React, Flutter 와 같은 프론트엔드 프레임워크등에서 주로 사용
MVVM 주요 컴포넌트
1. Model (모델)
- 애플리케이션의 데이터 구조를 나타내고 비즈니스 로직을 처리
- 데이터의 저장, 가져오기 및 비즈니스 규칙 적용을 담당
- 사용자 데이터 객체, 데이터베이스에서 가져오는 데이터, API 요청 결과 등
2. View (뷰)
- 사용자에게 정보를 표시하는 UI를 담당
- 사용자의 상호작용을 처리하며, 사용자 입력을 ViewModel로 전달
- 버튼, 텍스트 필드, 리스트 등
3. ViewModel (뷰모델)
- Model과 View 간의 연결고리 역할
- View에 필요한 데이터를 준비하고, 사용자가 View에서 입력한 내용을 처리하여 Model로 전달
- ViewModel은 View에 대한 구체적인 정보나 구현을 몰라야 하며, View에 대한 상태를 관리
- 버튼 클릭 시 데이터 가져오기, 텍스트 필드와의 상호작용
MVVM 패키지 구성 샘플
1. React
/src
/components // **View** - 사용자 인터페이스를 담당하는 컴포넌트들
/App.js
/UserForm.js
/models // **Model** - 데이터 구조와 관련된 클래스나 객체들
/UserModel.js
/viewmodels // **ViewModel** - View와 Model을 연결하는 뷰모델 파일
/UserViewModel.js
/services // **기타** - 데이터 요청 등을 처리하는 서비스 파일
/ApiService.js
/styles // **기타** - 스타일링 파일
/App.css
2. Java
/src
/com
/example
/app
/model // **Model** - 데이터 구조와 비즈니스 로직을 담당하는 클래스
/UserModel.java
/viewmodel // **ViewModel** - View와 Model을 연결하는 클래스
/UserViewModel.java
/view // **View** - 사용자 인터페이스(UI)를 담당하는 액티비티 파일
/UserActivity.java
3. C#
/src
/Models // **Model** - 데이터 및 비즈니스 로직을 담당하는 클래스
/UserModel.cs
/ViewModels // **ViewModel** - View와 Model을 연결하는 클래스
/UserViewModel.cs
/Views // **View** - 사용자 인터페이스(UI)를 담당하는 XAML 파일
/UserView.xaml
/App.xaml.cs // **기타** - 앱 초기화 및 설정 담당
4. Dart
/lib
/models // **Model** - 데이터 구조와 비즈니스 로직을 담당하는 클래스
/user_model.dart
/viewmodels // **ViewModel** - View와 Model을 연결하는 클래스
/user_viewmodel.dart
/views // **View** - 사용자 인터페이스(UI)를 담당하는 위젯
/user_page.dart
user_model.dart (Model)
class UserModel
{
final String name;
final String email;
UserModel({required this.name, required this.email});
}
user_view_model.dart (ViewModel)
import 'package:flutter/material.dart';
import 'user_model.dart';
class UserViewModel extends ChangeNotifier
{
UserModel? _user;
UserModel? get user => _user;
// 데이터를 가져오는 메서드는 ViewModel에서 처리
Future<void> loadUserData() async
{
await Future.delayed(Duration(seconds: 2)); // API 호출 시뮬레이션
_user = UserModel(name: 'John Doe', email: 'john.doe@example.com');
notifyListeners(); // 뷰에 변경 사항을 알림
}
}
user_page.dart (View)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'user_view_model.dart';
class UserPage extends StatelessWidget
{
@override
Widget build(BuildContext context)
{
return ChangeNotifierProvider(
create: (context) => UserViewModel()..loadUserData(),
child: Scaffold(
appBar: AppBar(
title: Text('User Information'),
),
body: Consumer<UserViewModel>(
builder: (context, viewModel, child)
{
if (viewModel.user == null)
{
return Center(child: CircularProgressIndicator());
}
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Name: ${viewModel.user!.name}', style: TextStyle(fontSize: 20)),
Text('Email: ${viewModel.user!.email}', style: TextStyle(fontSize: 20)),
],
),
);
},
),
),
);
}
}
main.dart (Main Application)
import 'package:flutter/material.dart';
import 'user_page.dart';
void main()
{
runApp(MaterialApp(
home: UserPage(),
));
}
MVVM 패턴의 장점
1. 유지보수성
- UI 로직(View)과 비즈니스 로직(Model)을 분리하여 코드의 응집도를 높음
- 변경이 있을 때 다른 부분에 영향이 적음
2. 테스트 용이성
- ViewModel은 UI와 독립적이므로, 단위 테스트(Unit Testing)가 용이
- UI와 관련된 로직을 직접 테스트
3. 재사용성
- ViewModel은 View와 독립적이므로, 다른 View에서 재사용 가능
- 같은 ViewModel을 사용하여 여러 화면에서 동일한 비즈니스 로직을 처리
4. 데이터 바인딩
- 데이터 바인딩을 통해 View와 ViewModel 간의 상호작용을 자동화
- 이를 통해 View와 ViewModel 간의 관계를 선언적으로 설정
MVVM 패턴의 단점
1. 복잡성
- 작은 애플리케이션에서는 MVVM을 사용하는 것이 오히려 불필요한 복잡성을 초래
- 패턴을 적절하게 적용하지 않으면 코드가 과도하게 분리되어 관리하기 어려움
2. 학습 곡선
- 데이터 바인딩과 같은 고급 개념을 사용하므로, 새로운 개발자나 해당 패턴에 익숙하지 않은 개발자에게는 학습이 필요