Flutter

[Flutter] 40. MVVM 구조란?

Song hyun 2024. 11. 13. 10:30
728x90
반응형

[Flutter] 40. MVVM 구조란?

 

1. MVVM 패턴의 정의

  • MVVM 패턴은 애플리케이션을 세 역할로 나눠, 유지 보수성과 재사용성을 높이는 디자인 패턴이다.
  • UI 업데이트와 상태관리는 플러터에서 필수적인 부분! -> MVVM 패턴을 사용해 코드 구조를 효율적으로 관리할 수 있다.

*MVVM 구조 + 클린 아키텍처 : 코드에 대한 기본적인 이해가 없다면 어렵다.

 

 

2. MVVM 패턴의 구성

  • Model: 애플리케이션의 데이터 구조와 비즈니스 로직을 담당한다. 데이터를 정의하거나 데이터를 처리하는 로직이 포함된다.
  • View: 사용자 인터페이스를 담당한다. Flutter에서는 화면에 표시되는 위젯들이 View 역할을 하고, ViewModel을 통해 화면에 데이터를 받아 표시한다.
  • ViewModel: 비즈니스 로직과 UI 사이의 중간 역할을 한다. View에서 받은 요청을 처리하고, Model에서 데이터를 가지고 와 View에 전달하는 역할을 한다.

 

 

3. 시나리오 코드

* 아래와 같은 폴더 구조를 가진다.

 

 

(1) Todo 클래스


// Todo의 모델 클래스 - 할 일 데이터를 정의
class Todo{

  String id;
  String title;

  Todo({required this.id,required this.title});
}

 

 

(2) ViewModel 클래스 - TodoViewModel


// ViewModel 클래스 - 상태와 로직을 담당한다

import 'package:mvvm_project_v01/start02/models/todo.dart';

class TodoViewModel{

  // 데이터가 필요하다
  List<Todo> todos = [];

  // 할 일을 추가하는 기능
void addTodo(String title){
  final newTodo = Todo(id: DateTime.now().toString(), title: title);
  todos.add(newTodo);
}

// 할 일을 삭제하는 기능
void removeTodo(String id){
  todos.removeWhere((todo)=>todo.id == id);
}
}

 

 

(3) view 클래스 - todo_screen.dart

import 'package:flutter/material.dart';
import 'package:mvvm_project_v01/start02/view_models/Todo_view_model.dart';


void main() => runApp(MaterialApp(home: TodoScreen()));

class TodoScreen extends StatefulWidget {
  const TodoScreen({super.key});

  @override
  State<TodoScreen> createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {

  // MVVM 패턴이기 때문에 View 는 ViewModel 클래스만 참조하면 된다.
  final TodoViewModel todoViewModel = TodoViewModel();
  final TextEditingController _controller = new TextEditingController();


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MVVM Basic Todo List'),
      ),
      body: Column(
        children: [
          // 입력 필드 만들기
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: InputDecoration(labelText: '작업을 입력 하시오'),
                  ),
                ),
                IconButton(
                  onPressed: (){
                    if(_controller.text.isNotEmpty){
                      setState(() {
                        todoViewModel.addTodo(_controller.text);
                      });
                    }
                  },
                  icon: Icon(Icons.add),
                )
              ],
            ),
          ),
          // 아래에 할일 목록 표시 구성
          Expanded(
            child: ListView.builder(
                itemCount: todoViewModel.todos.length,
                itemBuilder: (context, index) {
                  // 뷰모델에 있는 자료구조 안에 각 인덱스에 맵핑된 객체 Todo 인스턴스 하나
                  final todo = todoViewModel.todos[index];
                  return ListTile(
                    title: Text(todo.title),
                    trailing: IconButton(
                      icon: Icon(Icons.delete),
                      onPressed: () {
                        setState(() {
                          todoViewModel.removeTodo(todo.id);
                        });
                      },
                    ),
                  );
                }),
          ),
        ],
      ),
    );
  }
}
728x90
반응형