📝 Flutter MV 패턴 & MVVM 패턴 정리
Flutter에서 MV (Model-View) 패턴과 MVVM (Model-View-ViewModel) 패턴을 활용하여 코드의 유지보수성과 가독성을 높일 수 있습니다.
이번 포스팅에서는 MV → MVVM으로 발전하는 과정을 코드 예제와 함께 살펴보겠습니다.
1️⃣ MV (Model-View) 패턴 적용
👉 Model과 View만 존재하는 구조
👉 비즈니스 로직이 View에 포함됨 (View와 Model이 강하게 결합됨)
📌 Step 1: Model 생성 (todo_item.dart)
👉 Model은 데이터를 표현하는 역할을 담당
// Model
class TodoItem {
String title;
bool isDone;
TodoItem({required this.title, this.isDone = false});
}
📌 역할
- 데이터 구조를 정의 (title, isDone 속성 포함)
- 데이터의 상태를 저장 및 변경
📌 Step 2: View 생성 (todo_list_view.dart)
👉 View는 UI 화면을 담당
👉 사용자의 입력을 직접 처리하며, 상태 변경을 담당
import 'package:flutter/material.dart';
import 'package:flutter_statement_v01/_mvvm/_02/models/todo_item.dart';
class TodoListView extends StatefulWidget {
const TodoListView({super.key});
@override
State<TodoListView> createState() => _TodoListViewState();
}
class _TodoListViewState extends State<TodoListView> {
TextEditingController _controller = TextEditingController();
// 샘플 데이터
List<TodoItem> _todoItems = [
TodoItem(title: '플러터 공부'),
TodoItem(title: '낮잠 자기', isDone: true),
];
@override
Widget build(BuildContext context) {
return Flexible(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter todo item...',
suffixIcon: IconButton(
onPressed: () {
setState(() {
// 새로운 할 일을 추가하는 로직
_todoItems.add(TodoItem(title: _controller.text));
_controller.clear();
});
},
icon: Icon(Icons.add),
),
),
),
),
SizedBox(height: 16.0),
Expanded(
child: ListView.builder(
itemCount: _todoItems.length,
itemBuilder: (context, index) {
final TodoItem item = _todoItems[index];
return ListTile(
title: Text(item.title),
trailing: Checkbox(
value: item.isDone,
onChanged: (value) {
setState(() {
item.isDone = !item.isDone;
});
},
),
);
},
),
)
],
),
);
}
}
📌 문제점
- setState()를 사용하여 직접 상태를 관리.
- 비즈니스 로직 (데이터 추가, 체크박스 상태 변경 등)이 View에 포함됨.
- View가 Model을 직접 조작하여 강한 결합이 발생 → 유지보수 어려움.
2️⃣ MVVM (Model-View-ViewModel) 패턴 적용
👉 ViewModel을 추가하여 View와 Model을 분리
👉 ViewModel에서 비즈니스 로직을 처리하여 View의 역할을 단순화
📌 Step 1: Model (기존과 동일)
// Model
class TodoItem {
String title;
bool isDone;
TodoItem({required this.title, this.isDone = false});
}
📌 역할
- 데이터의 구조 및 상태 유지
- ViewModel에서 데이터를 관리하도록 지원
📌 Step 2: ViewModel 생성 (todo_list_view_model.dart)
👉 비즈니스 로직을 분리하여 View에서 직접 데이터를 조작하지 않도록 개선
import 'package:flutter_statement_v01/_mvvm/_02/models/todo_item.dart';
class TodoListViewModel {
List<TodoItem> _items = [];
// Getter (외부에서 _items 접근 가능)
List<TodoItem> get items => _items;
// 비즈니스 로직 - 할 일 추가
void addItem(String title) {
_items.add(TodoItem(title: title));
}
// 비즈니스 로직 - 완료 상태 변경
void toggleItem(TodoItem todo) {
todo.isDone = !todo.isDone;
}
}
📌 개선된 점
- addItem(), toggleItem()과 같은 비즈니스 로직을 ViewModel에서 관리.
- View에서 직접 데이터를 조작하지 않고 ViewModel을 통해서만 데이터 변경.
📌 Step 3: View 수정 (todo_list_view.dart)
👉 ViewModel을 사용하여 UI의 역할을 단순화
import 'package:flutter/material.dart';
import 'package:flutter_statement_v01/_mvvm/_02/models/todo_item.dart';
import 'package:flutter_statement_v01/_mvvm/_02/viewmodels/todo_list_view_model.dart';
class TodoListView extends StatefulWidget {
const TodoListView({super.key});
@override
State<TodoListView> createState() => _TodoListViewState();
}
class _TodoListViewState extends State<TodoListView> {
TextEditingController _controller = TextEditingController();
final TodoListViewModel _viewModel = TodoListViewModel();
@override
Widget build(BuildContext context) {
return Flexible(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'Enter todo item...',
suffixIcon: IconButton(
onPressed: () {
setState(() {
_viewModel.addItem(_controller.text);
_controller.clear();
});
},
icon: Icon(Icons.add),
),
),
),
),
SizedBox(height: 16.0),
Expanded(
child: ListView.builder(
itemCount: _viewModel.items.length,
itemBuilder: (context, index) {
final TodoItem item = _viewModel.items[index];
return ListTile(
title: Text(item.title),
trailing: Checkbox(
value: item.isDone,
onChanged: (value) {
setState(() {
_viewModel.toggleItem(item);
});
},
),
);
},
),
)
],
),
);
}
}
📌 개선된 점
- ViewModel을 사용하여 비즈니스 로직을 View에서 완전히 분리.
- View는 UI를 렌더링하는 역할만 수행하고, 데이터는 ViewModel에서 관리.
- 코드의 재사용성과 유지보수성이 향상.
📌 MV → MVVM 패턴 변환 과정 정리
단계 | 변경 내용 | 설명 |
1단계: MV | View에서 직접 상태 관리 | setState()를 사용하여 직접 Model을 변경 |
2단계: MVVM | ViewModel 추가 | ViewModel을 통해 상태를 변경하도록 개선 |
📝 결론
✅ MVVM 패턴을 사용하면 좋은 점
✔ UI와 비즈니스 로직을 분리하여 유지보수성을 향상할 수 있다.
✔ ViewModel을 활용하여 UI 상태를 관리하여 코드의 가독성을 높일 수 있다.
✔ ViewModel을 활용하면 테스트가 용이해진다.
MVVM을 적용하면 View는 UI만 관리하고, 비즈니스 로직은 ViewModel에서 처리하므로 코드가 더 깔끔하고 유지보수가 쉬워집니다! 🚀
MVVM 패턴이란?
[Flutter] MVVM 패턴에 대해서 알아 보자
📝 Flutter MVVM 패턴 정리Flutter에서 애플리케이션을 개발할 때, 유지보수성과 확장성을 높이기 위해 MVVM (Model-View-ViewModel) 패턴을 적용할 수 있습니다.이번 포스팅에서는 MVVM 패턴의 개념과 코드
seohong.tistory.com
'Flutter > Dart 언어' 카테고리의 다른 글
[Flutter] MVVM + 상태관리 (0) | 2025.02.05 |
---|---|
[Flutter] MVVM 패턴에 대해서 알아 보자 (0) | 2025.02.05 |
[Flutter] 상태(State)의 종류 (0) | 2025.02.03 |
[Flutter] 상태란 뭘까? (2) | 2025.01.20 |
Dio 패키지 사용해 보기 (1) | 2025.01.14 |