UI에서는 유지보수를 쉽기 위한 여러가지 디자인 패턴이 있습니다.
대표적으로는 MVC, MVP, MVVM가 있는데 여기선 MVC, MVP 2개만 다룰 예정입니다.
셋 다 목적은 같습니다!
한 곳에서 모든 것을 담당한다면 유지보수 하기 힘들기 때문에 각각 분할하여 역할을 나누는 것입니다.
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) {}
}
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);
}
}