Model-View-ViewModel (MVVM)은 소프트웨어 개발에서 널리 사용되는 아키텍처 패턴 중 하나로, 데이터 모델(Model), 사용자 인터페이스(View), 그리고 이 둘을 연결하는 비즈니스 로직과 데이터 처리 로직을 담당하는 뷰모델(ViewModel)로 구성됩니다. Flutter에서 Provider 패키지를 사용하여 MVVM 아키텍처를 구현할 수 있습니다. 이를 통해 데이터 관리와 UI 로직을 분리하여 앱의 유지보수성, 테스트 용이성, 그리고 확장성을 향상시킬 수 있습니다.
모델 정의: 데이터 구조와 관련 비즈니스 로직을 포함하는 모델 클래스를 정의합니다.
뷰모델 생성: ChangeNotifier
를 상속받는 클래스를 생성하고, 이 클래스 내에서 모델을 관리하며, View로부터의 사용자 입력을 처리하는 메서드를 정의합니다. 데이터가 변경되면 notifyListeners()
를 호출하여 View를 업데이트합니다.
Provider 설정: main.dart
또는 앱의 최상위에 있는 파일에서, ChangeNotifierProvider
를 사용하여 앱 전역에서 뷰모델 인스턴스에 접근할 수 있도록 설정합니다.
뷰 구현: Consumer
또는 context.watch()
와 같은 메서드를 사용하여 뷰모델로부터 데이터를 받아 UI를 구성합니다. 사용자 입력은 뷰모델로 전달되어 처리됩니다.
// Model
class UserData {
final String name;
final int age;
UserData(this.name, this.age);
}
// ViewModel
class UserViewModel extends ChangeNotifier {
UserData _user = UserData('John Doe', 30);
UserData get user => _user;
void updateUser(String name, int age) {
_user = UserData(name, age);
notifyListeners();
}
}
// main.dart
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => UserViewModel(),
child: MyApp(),
),
);
}
// View (A Flutter Widget)
class UserView extends StatelessWidget {
Widget build(BuildContext context) {
final viewModel = context.watch<UserViewModel>();
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Name: ${viewModel.user.name}'),
Text('Age: ${viewModel.user.age}'),
ElevatedButton(
onPressed: () => viewModel.updateUser('Jane Doe', 28),
child: Text('Update User'),
),
],
),
),
);
}
}
이 예시에서는 간단한 사용자 데이터를 관리하는 MVVM 아키텍처를 구현하고 있습니다. UserViewModel
은 사용자 데이터를 업데이트하는 로직을 포함하며, UI에서는 context.watch()
를 사용하여 모델의 변경사항을 감지하고 화면을 갱신합니다.
Provider와 MVVM 아키텍처를 함께 사용하면, 상태 관리를 효율적으로 수행하고, 앱의 구조를 더 명확하게 구분할 수 있습니다. 이는 큰 규모의 앱 개발과 팀 작업에 특히 유용합니다.
MVVM 아키텍처에 Repository
를 포함하여 Flutter 앱을 구성할 때, 데이터 레이어와 비즈니스 로직 레이어 사이에 추상화 레이어를 추가함으로써, 앱의 유지보수성과 테스트 용이성을 더욱 향상시킬 수 있습니다. Repository
는 데이터 소스(예: 웹 API, 로컬 데이터베이스)로부터 데이터를 가져오는 역할을 담당하며, 이 데이터를 ViewModel에 제공합니다. ViewModel은 이 데이터를 사용하여 View에 표시할 정보를 준비합니다.
아래 예제 코드는 Repository
를 포함한 MVVM 아키텍처를 구현하는 방법을 보여줍니다. 코드에는 MVVM 구성요소와 관련된 주석이 포함되어 있습니다.
// Model
class UserData {
final String name;
final int age;
UserData(this.name, this.age);
}
// Repository
class UserRepository {
// 데이터 소스로부터 사용자 데이터를 가져오는 메서드
Future<UserData> fetchUserData() async {
// 여기서는 가상의 API 호출이라고 가정합니다.
// 실제 앱에서는 여기서 웹 API를 호출하거나 로컬 데이터베이스를 쿼리할 수 있습니다.
return UserData('John Doe', 30); // 가상의 사용자 데이터 반환
}
}
// ViewModel
class UserViewModel extends ChangeNotifier {
final UserRepository userRepository;
// ViewModel이 생성될 때 UserRepository 인스턴스를 주입받습니다.
UserViewModel({required this.userRepository});
UserData _user = UserData('', 0);
UserData get user => _user;
// 사용자 데이터를 업데이트하는 메서드
Future<void> updateUser() async {
_user = await userRepository.fetchUserData();
notifyListeners(); // 데이터가 변경되었음을 리스너들에게 알림
}
}
// main.dart
void main() {
runApp(
ChangeNotifierProvider(
// UserViewModel을 생성하고 UserRepository 인스턴스를 주입합니다.
create: (context) => UserViewModel(userRepository: UserRepository()),
child: MyApp(),
),
);
}
// View
class UserView extends StatelessWidget {
Widget build(BuildContext context) {
// ViewModel에서 제공하는 사용자 데이터를 구독합니다.
final viewModel = context.watch<UserViewModel>();
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Name: ${viewModel.user.name}'),
Text('Age: ${viewModel.user.age}'),
ElevatedButton(
// 버튼을 누르면 ViewModel을 통해 사용자 데이터를 업데이트합니다.
onPressed: () => viewModel.updateUser(),
child: Text('Update User'),
),
],
),
),
);
}
}
이 코드는 UserRepository
를 통해 데이터를 가져오고, UserViewModel
에서 이 데이터를 관리하며, UserView
에서 사용자에게 데이터를 표시하는 방식으로 구성됩니다. ViewModel은 ChangeNotifier
를 상속받아 데이터 변경 시 View를 자동으로 업데이트할 수 있도록 합니다. ChangeNotifierProvider
는 앱의 최상위에서 ViewModel을 제공하며, context.watch<UserViewModel>()
을 사용하여 ViewModel의 데이터 변화를 구독합니다.
이 예시는 MVVM 아키텍처와 Repository 패턴을 통합하여 Flutter 앱에서 데이터 관리와 비즈니스 로직을 효과적으로 분리하는 방법을 보여줍니다. 이 구조는 앱의 확장성, 유지보수성, 그리고 테스트 용이성을 향상시키는 데 도움이 됩니다.
이 코드 예제는 Flutter에서 MVVM 아키텍처와 Repository 패턴을 사용하여 비디오 재생 설정(음소거, 자동 재생 등)을 관리하는 방식을 보여줍니다. MVVM 아키텍처는 Model, View, ViewModel의 세 가지 주요 구성 요소로 이루어져 있으며, Repository 패턴은 데이터 소스를 추상화하여 ViewModel과 데이터 소스 사이의 결합도를 낮춥니다. 이를 통해 유지보수성과 테스트 용이성이 향상됩니다.
Model (PlaybackConfigModel
): 애플리케이션의 데이터 구조를 정의합니다. 이 경우, 비디오의 음소거 및 자동 재생 설정을 나타냅니다.
View (VideoPost
, SettingsScreen
): 사용자 인터페이스를 구성하며, 사용자 입력을 ViewModel에 전달하고, ViewModel로부터 데이터 변화를 구독하여 UI를 업데이트합니다.
ViewModel (PlaybackConfigViewModel
): View와 Model 사이의 연결 고리 역할을 하며, 비즈니스 로직을 수행합니다. ChangeNotifier
를 상속받아 데이터 변경 시 View에 알립니다.
Repository (PlaybackConfigRepository
): 데이터 소스를 추상화하며, 여기서는 SharedPreferences
를 통해 음소거 및 자동 재생 설정을 로컬에 저장하고 불러옵니다. ViewModel은 Repository를 통해 이러한 설정을 관리합니다.
// PlaybackConfigModel: 설정 데이터 모델 정의.
class PlaybackConfigModel {
bool muted;
bool autoplay;
PlaybackConfigModel({
required this.muted,
required this.autoplay,
});
}
// PlaybackConfigRepository: 설정 데이터 관리를 위한 레포지토리.
// SharedPreferences를 사용해 설정을 로컬 저장소에 저장 및 로드.
class PlaybackConfigRepository {
final SharedPreferences _preferences;
PlaybackConfigRepository(this._preferences);
// 음소거 설정 저장 및 로드 메서드
Future<void> setMuted(bool value) async {
_preferences.setBool(_muted, value);
}
bool isMuted() {
return _preferences.getBool(_muted) ?? false;
}
// 자동 재생 설정 저장 및 로드 메서드
Future<void> setAutoplay(bool value) async {
_preferences.setBool(_autoplay, value);
}
bool isAutoplay() {
return _preferences.getBool(_autoplay) ?? false;
}
}
// PlaybackConfigViewModel: 비즈니스 로직과 View 업데이트 로직을 포함하는 ViewModel.
// Repository로부터 설정을 관리하고, 변경사항을 View에 알림.
class PlaybackConfigViewModel extends ChangeNotifier {
final PlaybackConfigRepository _repository;
late final PlaybackConfigModel _model;
PlaybackConfigViewModel(this._repository) {
_model = PlaybackConfigModel(
muted: _repository.isMuted(),
autoplay: _repository.isAutoplay(),
);
}
// 음소거 및 자동 재생 설정에 대한 getter와 setter.
bool get muted => _model.muted;
void setMuted(bool value) {
_repository.setMuted(value);
_model.muted = value;
notifyListeners(); // 변경 사항을 View에 알림.
}
bool get autoplay => _model.autoplay;
void setAutoplay(bool value) {
_repository.setAutoplay(value);
_model.autoplay = value;
notifyListeners();
}
}
이 코드는 SharedPreferences
를 사용하여 사용자의 비디오 재생 설정을 로컬 저장소에 저장하고, 이 설정을 앱 전체에 걸쳐 관리하는 방법을 보여줍니다. PlaybackConfigViewModel
은 설정의 변경을 처리하고, 이 변경 사항을 View에 알려 UI를 업데이트합니다. PlaybackConfigRepository
는 데이터의 지속성을 관리하며, ViewModel과 Model 사이의 결합도를 낮춥니다.
이러한 구조를 통해, 앱의 데이터 관리와 비즈니스 로직을 UI 로직으로부터 분리하여, 앱의 유지보수성과 확장성을 향상시킬 수 있습니다.