[Unity] UI 아키텍처 패턴

AsiaticRicecake·2025년 5월 12일

UI에서는 유지보수를 쉽기 위한 여러가지 디자인 패턴이 있습니다.
대표적으로는 MVC, MVP, MVVM가 있는데 여기선 MVC, MVP 2개만 다룰 예정입니다.

셋 다 목적은 같습니다!
한 곳에서 모든 것을 담당한다면 유지보수 하기 힘들기 때문에 각각 분할하여 역할을 나누는 것입니다.

1. 📖 MVC (Model - View - Controller)

MVC는 Model - View - Controller으로 분할하여 관리하는 개념입니다.

✅ Model
: 데이터 부분을 담당합니다.
(플레이어 체력, 점수 등 게임 데이터)

✅ View
: UI 표시 되는 부분을 말하는데 데이터를 그래픽으로 만들고 화면에 렌더링합니다. (유저가 보는 버튼, 텍스트, 이미지)

✅ Controller
: 실제 동작하도록 데이터를 입력 받았을 때 연산하는 로직 처리를 담당합니다.
(버튼 클릭 처리)

1️⃣ PlayerModel에서는 데이터만 관리하고

public class PlayerModel 
{
    public int Health { get; set; }
}

2️⃣ PlayerController에서는 데이터를 받아 로직을 만들고

public class PlayerController 
{
    private PlayerModel model;
    private PlayerView view;

    public PlayerController(PlayerModel model, PlayerView view) 
    {
        this.model = model;
        this.view = view;
        view.OnDamage += DamagePlayer;
    }

    public void DamagePlayer(int damage) 
    {
        model.Health -= damage;
        view.UpdateHealth(model.Health);
    }
}

3️⃣ PlayerView에서는 UI에 집중하도록 분할하여 관리합니다.

public class PlayerView : MonoBehaviour 
{
    public UnityAction<int> OnDamage;
    public void OnClickDamageButton() 
    {
        OnDamage?.Invoke(10);
    }

    public void UpdateHealth(int health) {}
}

2. 📖 MVP (Model - View - Presenter)

MVP는 Model - View - Presenter로 분할하여 관리하는 개념입니다.

MVC와 MVP 모두 Model 변경 시 View 갱신되는 것은 같지만 차이가 있습니다.

MVC에서는 View가 Controller 통해 Model을 변경합니다.
Model이 변경되면 Controller가 View에 알려주거나, View가 Model에서 직접 읽습니다.

하지만 MVP에서는 View가 Presenter 호출만 하고
Presenter가 Model을 변경 후 Presenter가 View에 UI 갱신 명령을 주는 방식입니다.
결국 View는 Model을 직접 참조하는 형식이 아니라서 결합도가 낮습니다.

✅ Model
: 데이터 부분만 담당

✅ View
: UI만 담당

✅ Presenter
: View와 Model을 연결하는데, View에만 명령을 내려줍니다.

1️⃣ Model(PlayerModel) → 데이터만 관리

public class PlayerModel
{
    public int Health { get; private set; } = 100;

    public void TakeDamage(int damage) {
        Health = Mathf.Max(0, Health - damage);
    }
}

2️⃣ View(PlayerView) → UI 표시/버튼 처리만 하도록 설계

public interface IPlayerView 
{
    void SetPresenter(PlayerPresenter presenter);
    void DisplayHealth(int health);
}
public class PlayerView : MonoBehaviour, IPlayerView 
{
    public Text healthText;
    public Button damageButton;

    public PlayerPresenter presenter;

    public void Start() 
    {
        damageButton.onClick.AddListener(OnDamageButtonClicked);
    }

    public void SetPresenter(PlayerPresenter presenter) 
    {
        this.presenter = presenter;
    }

    public void DisplayHealth(int health) 
    {
        healthText.text = $"Health: {health}";
    }

    private void OnDamageButtonClicked() 
    {
        presenter.DamagePlayer(10);
    }
}

3️⃣ Presenter(PlayerPresenter) → Model이 변경되고, View가 갱신되도록 설계

public class PlayerPresenter 
{
    private PlayerModel model;
    private IPlayerView view;

    public PlayerPresenter(PlayerModel model, IPlayerView view) 
    {
        this.model = model;
        this.view = view;
        this.view.SetPresenter(this);
        UpdateUI();
    }

    public void DamagePlayer(int damage) 
    {
        model.TakeDamage(damage);
        UpdateUI();
    }

    public void UpdateUI() 
    {
        view.DisplayHealth(model.Health);
    }
}

0개의 댓글