[20260121] - 디자인패턴 1

SmartBear·2026년 1월 21일
post-thumbnail

유니티 디자인

컴포넌트 패턴

  • 기능들의 조합으로 디자인 하는 방법.
  • 코드가 아래와 같이 될 경우 적용하면 좋음.
    • 매번 새 클래스를 만들어야 함
    • 또한 클래스가 너무 커짐
    • 한 클래스내 많은 기능이 집약됨
    • 결국 스파게티 코드가 생성됨
  • 객체 ⬅️ 기능의 묶음

vs 상속

상속은, 객체지향에서도 다뤘듯이, 부모의 성질을 자식이 물려 받아 구현하는 방식이다. (여기서의 성질은 필드, 메소드 둘다를 의미한다.)
따라서 부모가 갖고 있는 내용에 대한 재정의, 혹은 자식만이 갖고 있는 성질을 덧붙이며 특정 계열에 대한 정의하는데 유리하다.

반면에 인터페이스는 각 클래스가 갖고 있을 기능 만을 떼어내어 해당 기능을 갖고 있어야 할 클래스를 생성할 수 있어 클래서 정의가 유연하다.
뿐만 아니라, 해당 기능을 갖고 있는 클래스에 대한 필터링 역할도 할 수 있어 유용하게 사용할 수 있다.

위에 언급했듯, 상속인터페이스 모두 유용하지만, 게임 프로그래밍 적으로 상속의 깊이가 너무 깊어지는 경향이 발생할 수 있다.
이럴 경우 자식클래스에서는 어떤 상속이 되었는지 확인이 어려울 뿐 아니라, 중간 혹은 부모 클래스의 변동에 의해 자식 클래스의 변경이 심할 경우도 발생한다.
또한, 아무래도 상하 관계, 그것도 Top-down 방식의 계승이다보니 확장성이 조금 떨어진다는 문제점도 있다.

인터페이스는 그에 반해 확장성이 매우 뛰어나기 때문에 이를 활용하는 것이 조금 더 유리할 수 있다.

유니티는 기본적으로 컴포넌트 기반의 설계를 권고하고 있다. (에디터 자체도 그렇게 생겼다.)
때문에 인터페이스 기반 디자인인 컴포넌트 패턴을 활용한 설계가 조금 더 유리 할 수 있다.

간편 예제

public interface IMove
{
    public void Invoke(Vector2 input);
}

public class PlayerController : MonoBehaviour
{
    IMove move;
    private void Start()
    {
        move = GetComponent<IMove>();  // 컴포넌트로 인터페이스를 불러올 수 있다! (꿀기능!!)
    }

    private void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector2 input = new Vector2(h, v);
        
        move?.Invoke(input);
    }
}

싱글톤

싱글톤은 실행되는 프로세스 내 전역적으로 관리되는 유일 무이한 객체를 이용하는 디자인을 말한다.

개인적으로 Python 은 기본적으로 싱글톤 인터프리터 형식이었기 때문에 이 점에 대해 이해하는 데는 큰 어려움은 없었다.

공유된 메모리내 데이터 및 기능을 사용하기 때문에 접근이 쉽고 관리도 쉽다.

주의 사항 및 단점

  • 생명주기와 책임을 통제 가능할 때만 사용.
  • 결합도가 높으며 객체지향의 원칙 중 하나인 DIP 를 위반한다.

주요 함수

  • 유니티에서 싱글톤은 특정 객체를 다른 씬에서는 생성이 불가능 하되, 미리 생성한 씬을 삭제/추가 하지 않고 그대로 사용할 수 있게 하는 함수를 제공한다.
  • DontDestoryOnLoad(gameObject); 지정된 객체가 사라지지 않도록 한다.

간편 예제

// GameManager.cs
public class GameManager : MonoBehaviour
{
    private static GameManager _instance;  // static 주의
    
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        GenerateManager<SomeManager>();
    }

    private void GenerateManager<T>() where T: Component
    {
        if (FindObjectOfType<T>() != null) return;
        var go = new GameObject(typeof(T).Name);  // 컴포넌트 이름으로 게임 object 인스턴스화
        go.AddComponent<T>();  // 컴포넌트 추가 -> Awake 발생
        DontDestroyOnLoad(go);  // 싱글톤화
    }

}

// SomeManager.cs
public class SomeManager : MonoBehaviour
{
    public static SomeManager Instance { get; private set; }   // static 주의

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);        
    }
}

주로 싱글톤화 시키는 컴포넌트

  • GameManager
    • 게임 자체의 제어를 담당하는 중추적인 역할로 많이 사용한다(고한다).
    • 생성하면 Unity 에디터에서 톱나바퀴 모양의 아이콘으로 관리된다. (라고 강의 영상에서는 이야기 했는데 난 안되는...)
  • UI; UI 에 대한 내용. 게임내 씬이 많고 공통적으로 사용해야 하는 UI 에 대해 주로 사용될 것이다.
  • Data; DB 를 따로 운영하지 않는 한 접근 및 관리가 편할 것이다.
  • Audio; 소리를 다른 씬에서도 재활용하여 사용하는 경우가 많기 때문에 적절하다.
  • Scene; 동일한 씬이 여러개가 될 일은 많이 없다.
  • 그 밖에; 시작부터 끝까지 동일한 데이터와 기능을 유지해야 하는 내용에 대해 활용할 수 있을 것이다.
profile
Python Dev with Infra -> Game Programmer

0개의 댓글