유니티 제네릭을 사용하여 유연한 이벤트 관리 시스템 구현하기 #옵저버 패턴

옵저버 패턴과 유사하다고 짚고 넘어가겠습니다.

 

이번 포스팅에서는 이벤트 관리 시스템을 제네릭 타입을 사용하여 구현하였습니다.

제네릭을 사용함으로써 다양한 타입의 데이터를 유연하게 처리할 수 있으며, 여러 이벤트에 맞는 데이터를 효율적으로 전달하는 방법에 대해 알아보겠습니다.


제네릭을 사용한 EventManager 구현

public class EventArgs<T> : EventArgs
{
    public T Data { get; }

    public EventArgs(T data)
    {
        Data = data;
    }
}

EventArgs<T>는 제네릭 타입을 사용하여 데이터를 담을 수 있습니다. 이벤트가 발생할 때, 특정 타입의 데이터를 전달할 수 있도록 합니다.

 

EventArgs를 상속받는 이유는 .NET 프레임워크와 C#의 이벤트 시스템에서 표준화된 패턴을 따르기 위해서입니다. C#에서 이벤트를 정의할 때 주로 이벤트 핸들러는 두 가지 파라미터를 가집니다.

 

이벤트를 발생시키는 객체(주체) - Sender

이벤트의 추가 정보를 담은 객체 - EventArgs

 

 


이벤트 관리 시스템 - EventManager 클래스

// 이벤트 타입 정의
public enum EventType
{
    PlayerMoved, // 플레이어가 이동할 때의 이벤트
}
public static class EventManager
{
    // 이벤트 리스너를 관리하는 딕셔너리
    private static readonly Dictionary<EventType, Action<EventArgs<object>>> _eventDictionary 
	= new ();

    // 리스너 등록
    public static void AddListener(EventType eventType, Action<EventArgs<object>> listener)
    {
        if (_eventDictionary.ContainsKey(eventType))
        {
            _eventDictionary[eventType] += listener;
        }
        else
        {
            _eventDictionary[eventType] = listener;
        }
    }

    // 리스너 제거
    public static void RemoveListener(EventType eventType, Action<EventArgs<object>> listener)
    {
        if (_eventDictionary.ContainsKey(eventType))
        {
            _eventDictionary[eventType] -= listener;
        }
    }

    // 이벤트 발생
    public static void PostNotification<T>(EventType eventType, EventArgs<T> args)
    {
        if (_eventDictionary.TryGetValue(eventType, out var listeners))
        {
            // 제네릭 타입을 object로 캐스팅하여 전달
            listeners?.Invoke(args as EventArgs<object>);
        }
    }
}

 

  • AddListener: 특정 이벤트 타입에 리스너를 등록합니다. 리스너는 해당 이벤트가 발생하면 실행되는 콜백 함수입니다.
  • RemoveListener: 특정 이벤트 타입에 등록된 리스너를 제거합니다.
  • PostNotification: 이벤트가 발생했을 때, 등록된 모든 리스너에게 알림을 보내고 데이터를 전달합니다.

사용예시

플레이어가 이동하는 이벤트가 발생할 때,

private void MovePlayer(Vector3 direction)
{
    transform.position += direction;

    // 플레이어 이동 이벤트 발생
    EventManager.PostNotification(EventType.PlayerMoved, new EventArgs<Vector3>(transform.position));
}

 

UI에서는 플레이어가 이동한 이벤트를 처리합니다.

private void OnEnable()
{
	//이벤트 등록
    EventManager.AddListener(EventType.PlayerMoved, OnPlayerMoved);
}

private void OnPlayerMoved(EventArgs<object> args)
{
    Vector3 position = (Vector3)args.Data;
    Debug.Log($"Player moved to: {position}");
}