TIL

[UE5] ProjectFT#2 MVVM 패턴 적용 및 역할 분리

think95592 2026. 7. 6. 20:59

MVVM 패턴을 적용한 이유

기존에는 UI 위젯이 데이터 조회와 화면 표시를 모두 담당하는 구조였다.

이 방식은 UI가 복잡해질수록 위젯의 책임이 커지고, 유지보수가 어려워지는 문제가 있었다.

이를 개선하기 위해 MVVM(Model-View-ViewModel) 패턴을 적용하여 각 역할을 명확하게 분리하였다.


MVVM 개념 이해

MVVM은 데이터를 관리하는 부분과 화면을 그리는 부분을 분리하기 위한 디자인 패턴이다.

Model
    │
    ▼
ViewModel
    │
    ▼
View

각 구성 요소의 역할은 다음과 같다.

Model

게임의 실제 데이터를 관리하는 계층이다.

예시

  • InventoryComponent
  • ShopSubsystem
  • QuestSubsystem
  • DataTable
  • DataAsset

Model은 UI를 직접 알지 않는다.


View

사용자에게 화면을 보여주는 계층이다.

예시

  • Widget
  • Button
  • TextBlock
  • ListView

View는 데이터를 직접 계산하지 않고, ViewModel이 전달한 데이터를 화면에 표시하는 역할만 담당한다.


ViewModel

Model과 View 사이를 연결하는 계층이다.

Model에서 필요한 데이터를 가져와 UI에서 사용하기 좋은 형태로 가공하여 View에 전달한다.


ViewModel이 UI용 데이터를 가공하는 이유

게임 데이터는 UI에서 바로 사용하기 어려운 경우가 많다.

예를 들어 상점 아이템이라면

Model에는

  • 아이템 정보
  • 가격
  • 구매 가능 여부

등의 데이터가 각각 존재한다.

하지만 UI는

  • 아이콘
  • 이름
  • 가격 표시
  • 구매 가능 여부 색상

처럼 화면에 필요한 정보만 필요하다.

ViewModel은 이러한 데이터를 UI에 맞게 가공하여 전달한다.

덕분에 View는 데이터를 계산하지 않고 화면 표시에만 집중할 수 있다.


ListObject와 EntryWidget의 역할 변화

MVVM을 적용하면서 ListView 구조도 더욱 명확해졌다.

ListObject

ViewModel이 생성하는 UI 전용 데이터 객체이다.

ListView에 전달되는 데이터를 보관하는 역할을 한다.

ViewModel
    │
    ▼
ListObject

EntryWidget

ListObject의 데이터를 받아 화면에 표시하는 역할만 담당한다.

ListObject
    │
    ▼
EntryWidget

EntryWidget은 데이터를 계산하거나 검색하지 않고,

전달받은 데이터를 그대로 출력하도록 구성하였다.


MainViewModel과 PanelViewModel 분리

초기에는 하나의 ViewModel이 모든 UI를 관리하는 구조였다.

MainViewModel

├─ Inventory
├─ Shop
├─ Quest
├─ Storage
└─ Craft

기능이 늘어날수록 하나의 ViewModel이 너무 많은 책임을 가지게 되었다.

이를 개선하기 위해 기능별 ViewModel로 분리하였다.

MainViewModel
        │
        ├── ShopViewModel
        ├── InventoryViewModel
        ├── StorageViewModel
        ├── CraftViewModel
        └── QuestViewModel

MainViewModel은 전체 UI 흐름을 관리하고,

각 PanelViewModel은 자신의 기능만 담당하도록 역할을 나누었다.


느낀 점

MVVM은 단순히 클래스를 늘리는 패턴이 아니라 각 클래스의 책임을 명확하게 분리하기 위한 구조라는 것을 이해하게 되었다.

특히 ViewModel이 데이터를 가공하고, View는 화면만 담당하도록 역할을 나누면서 UI 코드의 복잡도가 크게 줄어들었다.

또한 MainViewModel과 PanelViewModel을 분리하면서 기능이 추가되더라도 기존 코드를 크게 수정하지 않고 확장할 수 있는 구조를 만들 수 있었다.