본문 바로가기

System Design/Design Patterns

[ Design Patterns ] MVVM 디자인 패턴이란?

MVVM(Model-View-ViewModel) 란?

- UI 애플리케이션에서 사용되는 디자인 패턴(사용자가 프로그램과 상호작용할 수 있도록 설계된 애플리케이션)

- 사용자 인터페이스(UI)와 애플리케이션의 비즈니스 로직을 분리하여 유지보수성과 테스트 용이성을 향상

- Angular, React, Flutter 와 같은 프론트엔드 프레임워크등에서 주로 사용

MVVM 주요 컴포넌트

1. Model (모델)

- 애플리케이션의 데이터 구조를 나타내고 비즈니스 로직을 처리

- 데이터의 저장, 가져오기 및 비즈니스 규칙 적용을 담당

- 사용자 데이터 객체, 데이터베이스에서 가져오는 데이터, API 요청 결과 등

 

2. View (뷰)

- 사용자에게 정보를 표시하는 UI를 담당

- 사용자의 상호작용을 처리하며, 사용자 입력을 ViewModel로 전달

- 버튼, 텍스트 필드, 리스트 등

 

3. ViewModel (뷰모델)

- ModelView 간의 연결고리 역할

- 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. 학습 곡선

- 데이터 바인딩과 같은 고급 개념을 사용하므로, 새로운 개발자나 해당 패턴에 익숙하지 않은 개발자에게는 학습이 필요