본문 바로가기

사이드 프로젝트

UI 관리를 제네릭으로 관리

 

1. UI 매니저 클래스 설계

- UIManager 클래스를 만들어 UI 요소를 관리.

- 해당 클래스는 싱글톤으로 디자인

- 제네릭 타입을 사용하여 여러 유형의 UI 요소를 관리

public class UIManager<T> where T : MonoBehaviour
{
	private static UIManager<T> instance;
    
    public static UIManager<T> Instance
    {
    	get
        {
        	if (instance == null)
            {
            	instance = new UIManager<T>();
             }
             return instance;
         }
     }
     
     // UI 요소를 관리하는 로직 추가
}

 

 

2. UI 프리팹 딕셔너리 사용

- UI 프리팹을 딕셔너리에 저장하여 동적으로 생성하거나 표시

public class UIManager<T> where T : MonoBehaviour
{
    private Dictionary<string, T> uiPrefabs = new Dictionary<string, T>();

    // UI 프리팹 등록
    public void RegisterUIPrefab(string key, T prefab)
    {
        if (!uiPrefabs.ContainsKey(key))
        {
            uiPrefabs.Add(key, prefab);
        }
    }

    // UI 생성
    public T InstantiateUI(string key, Transform parent)
    {
        if (uiPrefabs.TryGetValue(key, out T prefab))
        {
            T instance = Object.Instantiate(prefab, parent);
            return instance;
        }
        return null;
    }
}

 

3. 이벤트 시스템 활용

- 옵서버 패턴을 사용하여 UI 갱신 및 상호 작용을 관리

- UI 갱신을 위해 이벤트를 발생시키고, 필요한 곳에서 해당 이벤트를 구독하여 UI를 업데이트

public class UIEventSystem
{
    public static event Action<string> OnUIUpdate;

    public static void TriggerUIUpdate(string uiKey)
    {
        OnUIUpdate?.Invoke(uiKey);
    }
}

 

 

제네릭을 사용하면 함수나 클래스를 정의할 때 타입을 명시하지 않고, 나중에 사용될 때까지 일반적인 형식(T)으로 유지할 수 있다. 이는 코드의 유연성을 향상하고 중복 코드를 줄일 수 있다.

 

다음은 제네릭을 사용하지 않은 간단한 예제이다.

// 정수 형식만 다루는 클래스
public class IntProcessor
{
    public int Process(int x, int y)
    {
        return x + y;
    }
}

// 문자열 형식만 다루는 클래스
public class StringProcessor
{
    public string Process(string x, string y)
    {
        return x + y;
    }
}

 

 

그리고 위의 코드를 제네릭을 사용하여 개선하면 아래의 코드처럼 작성이 가능하다.

public class Processor<T>
{
    public T Process(T x, T y)
    {
        return (dynamic)x + (dynamic)y;
    }
}

 

여기서 'T'는 제네릭 형식 매개변수로, 나중에 사용될 때 실제 형식으로 대체된다. 이렇게 하면 Processor 클래스는 정수, 문자열 또는 다른 형식에 대해 동일한 기능을 수행할 수 있다.

 

제네릭은 특히 컬렉션과 같은 데이터 구조에서 많이 사용된다. 예를 들어, List<T> 나 Dictionary <TKey, TValue>와 같은 클래스들은 제네릭을 사용하여 여러 형식의 요소를 저장하고 다룰 수 있도록 한다.

 

또한 제네릭을 활용하면 다양한 유형의 컴포넌트나 기능을 일반화할 수 있다. 

 

 

public class UIManager : Singleton<UIManager>
{
    // Resources/Prefabs/UI 안의 UI 컴포넌트 프리팹들을 저장하는 딕셔너리
    Dictionary<string, UI_Base> uiDic = new Dictionary<string, UI_Base>();

    public T GetUIComponent<T>() where T : UI_Base
    {
        string key = typeof(T).Name;
        if (!uiDic.ContainsKey(key))
        {
            // 요청 시점에 해당 UI 컴포넌트가 없다면 Load
            var obj = Instantiate(Resources.Load($"Prefabs/UI/{key}"));
            uiDic.Add(key, obj.GetComponent<T>());
        }
        return (T)uiDic[key];
    }

    public void RemoveUIComponent<T>() where T : UI_Base
    {
        string key = typeof(T).Name;
        if (uiDic.ContainsKey(key))
        {
            uiDic.Remove(key);
        }
    }
}

 

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject go = new GameObject(typeof(T).Name);
                _instance = go.AddComponent<T>();

                DontDestroyOnLoad(_instance);
            }
            return _instance;
        }
    }
}

 

public class UI_Base : MonoBehaviour
{
    public virtual void OpenUI()
    {
        gameObject.SetActive(true);
    }

    public virtual void CloseUI()
    {
        gameObject.SetActive(false);
    }
}