2024. 12. 9. 19:50ㆍSTUDY/디자인 패턴
이 글은 'level up your code with game programming patterns' 서적을 기반으로 각종 블로그에서 추가적인 정보를 얻어 작성하였습니다.
[MVC 패턴]
MVC(모델 뷰 컨트롤러) (이하 MVC) 패턴은 사용자 인터페이스를 개발할 때 흔히 사용되는 일련의 디자인 패턴이다. MVC의 기본 아이디어는 소프트웨어의 논리적 부분과 데이터 및 프레젠테이션에서 분리하는 것이다. 그러면 불필요한 종속 관계를 줄이는 데 도움이 되며, 잠재적으로 스파게티 코드도 줄일 수 있다.
이름에서 알 수 있듯 MVC 패턴은 다음 3가지의 레이어로 분할된다.
- Model : 데이터를 저장한다. 모델은 전적으로 값을 저장하는 데이터 컨테이너이며 게임플레이 로직이나 계산을 수행하지 않는다.
- View : 인터페이스이다. 뷰는 데이터의 그래픽 표현을 형식화하고 화면에 렌더링한다.
- Controller : 로직을 처리한다. 두뇌라고 보면 된다. 컨트롤러는 게임 데이터를 처리하며 값이 런타임에 어떻게 변경되는지 산출한다.
MVC 디자인은 각 레이어가 수행하는 작업을 제한한다. 한 부분은 데이터를 저장하고 다른 부분은 데이터를 처리하고, 나머지 부분은 해당 데이터를 사용자에게 표시한다. SOLID의 단일 책임 원칙의 연장선으로 각 부분이 하나의 작업을 제대로 수행하며, 이는 MVC 아키텍처가 가진 장점 중 하나이다.
MVC 패턴의 핵심 원칙은 MVC패턴에서 각각의 역할을 명확히 분리하는 것이 중요하다.
[MVP 패턴]
MVP(모델 뷰 프리젠터)에서도 세 가지의 레이어로 분리한다. 하지만 각 부분이 맡은 책임이 조금씩 다르다.
MVP에서는 프리젠터(MVC에서 컨트롤러)가 다른 레이어의 중개자 역할을 한다.
모델로부터 데이터를 검색한 다음 뷰에 표시할 수 있도록 형식을 지정한다. MVP는 입력을 처리할 레이어를 컨트롤러가 아니라 뷰에서 사용자 입력을 처리하도록 변경한다.
게임으로 예시를 든다면 게임의 버튼이 입력되면 뷰 레이어는 UI 이벤트를 통해 프리젠터에 이 입력을 되돌려 보내고, 프리젠터는 모델을 조작한다. 이때 모델의 데이터가 업데이트가 되었음을 프리젠터에 알린다. 이후 프리젠터가 수정된 데이터를 뷰로 전달하면 UI가 이를 받아들이고 업데이트가 된다.
예시
캐릭터나 아이템의 체력을 표시하는 간단한 시스템을 떠올려 보자. 이를위해 Health라는 클래스를 만들 것이다.
데이터와 UI가 혼합된 클래스 하나에 모든 요소를 채울 수도 있겠지만 그렇게하면 확장성이 떨어질 수 있다. 기능을 더 추가하게되면 그만큼 복잡도가 증가할 것이다. 대신, Health 컴포넌트를 보다 MVP 중심적인 방식으로 구현할 수있다. 스크립트를 Health 및 HealthPresenter로 나눈다.
using System;
public class Health
{
public Action HealthChanged;
private const int minHealth = 0;
private const int maxHealth = 100;
private int currentHealth;
public int CurrentHealth { get { return currentHealth; } set { currentHealth = value; } }
//체력 증가
public void Increment(int amount)
{
currentHealth += amount;
currentHealth = Math.Clamp(currentHealth, minHealth, maxHealth);
UpdateHealth();
}
//체력 감소
public void Decrement(int amount)
{
currentHealth -= amount;
currentHealth = Math.Clamp(currentHealth, minHealth, maxHealth);
UpdateHealth();
}
//체력에 변경이 일어났을때 알린다.
public void UpdateHealth()
{
HealthChanged?.Invoke();
}
}
public class HealthPresenter
{
private Health health;
private int healthCount;
//해당 프레젠터가 초기화될때 호출될 함수
private void Init()
{
if (health != null)
health.HealthChanged += OnHealthChanged;
}
//해당 프레젠터가 더이상 사용하지 않을때 호출될 함수
private void OnDestory()
{
if (health != null)
health.HealthChanged -= OnHealthChanged;
}
//데미지를 입었다.
public void Damage(int amount)
{
health?.Decrement(amount);
}
//힐을 받았다.
public void Heal(int amount)
{
health?.Increment(amount);
}
//UI 갱신을 한다.
public void UpdateView()
{
if (health == null)
return;
healthCount = health.CurrentHealth;
}
//UI 갱신을 알린다.
public void OnHealthChanged()
{
UpdateView();
}
}
예시 코드에서 Health는 모델 역할을 한다. 값이 변경될때마다 실제 체력값을 저장하고 HealthChanged 이벤트를 호출한다. Health에는 게임 플레이 로직이 포함되지 않으며, 데이터를 늘리거나 줄이는 메서드만 있다. 체력에 변화를 주기 위해 우리는 HealthPresenter를 사용해야 한다. HealthPresenter에서는 실제 체력이 변경되었을때 뷰에게 UI를 갱신하라고 한다.
MVC 및 MVP는 큰 규모의 프로젝트에서 장점을 보인다. UI 개발과 업데이트를 나머지 코드 베이스와 거의 독립적으로 수행할 수 있다. 이로 인해 뷰를 담당하는 개발자, 로직을 담당하는 개발자 등 원활한 업무 분배가 가능하다. 물론 이를 위해 초기 설계에 많은 신경을 써야 할 것이다.
'STUDY > 디자인 패턴' 카테고리의 다른 글
[Design Pattern] 커맨드 패턴(Command pattern) (1) | 2024.12.09 |
---|---|
[Design Pattern] 팩토리 패턴(Factory Pattern) (0) | 2024.12.09 |
SOLID 원칙 (0) | 2024.12.08 |
Static, 싱글톤 (0) | 2022.07.01 |