💡 Quotation
소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다. Wikipedia
싱글톤 패턴은 위 내용처럼 프로그램이 가동된 후 딱 하나의 인스턴스만 갖는 객체를 말합니다. 전역 변수의 개념이 있으며 해당 객체의 포인터를 알고 있다면 글로벌한 성격을 가질 수도 있습니다! 👍
하지만 전역 및 글로벌 변수들이 많으면 스파게티 코드가 된다는 단점이 있으며 사용하는 순간 종속되기 때문에 단위 테스트의 어려움을 가질수 있습니다. 따라서 구현 전에 적절한 설계가 반드시 필요합니다.
프로그램이 실행되고 한 개의 인스턴스만 가져야 하는 것들이 무엇이 있을까요? 아마도 로거, 네트워크, 파일IO 처리, 등이 있을 것 같네요! 😎
유니티에서의 싱글톤#
유니티 세계에서 모든 객체는 MonoBehaviour
라는 클래스를 상속 받아 사용하게 됩니다. 해당 클래스를 상속 받으면 유니티의 생명주기라고 할 수 있는 Awake
, Start
, Update
와 같은 함수를 사용할 수 있게 됩니다.
싱글톤을 이용해서 만든 객체에서 백그라운드(코루틴)에서 실행해야 할 것들도 있을 것 같아 MonoBehaviour
를 상속 받아 만들기로 했습니다.
싱글톤 구현 방법#
구글링해서 찾아보니 싱글톤을 구현하는 방법은 여러가지가 있는 것 같았습니다. Hierarchy 에 게임 오브젝트를 만들고 스크립트를 추가해서 만드는 방법, 스크립트에서 직접 게임 오브젝트를 만드는 방법 등등..
저는 스크립트에서 게임 오브젝트를 직접 만드는 방법을 선택했습니다. UI가 아닌 단순 어떠한 기능을 구현하는 객체가 Hierarchy 에 떠 있는 것이 필요 없다고 생각했기 때문입니다.
또한 싱글톤을 만들기 위한 코드를 필요할 때 마다 중복으로 작성하는 것이 싫어 Template
을 이용했습니다. 아래는 싱글톤을 만들기 위한 템플릿 코드입니다.
💡 저는 싱글톤 패턴 객체는 끝에 ~Manager 라고 명명하여 사용하고 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| using UnityEngine;
public class TemplateManager<T> : MonoBehaviour where T : MonoBehaviour
{
private static object mutex = new object(); // Instance 요청에 대한 mutex
private static T instance = null; // 싱글톤 패턴의 핵심 요소 1
protected static bool isDestroy = false;
public static T Instance // 싱글톤 패턴의 핵심 요소 2
{
get
{
lock (mutex)
{
if (isDestroy)
return null;
instance = FindFirstObjectByType<T>();
// 인스턴스가 없다면 새로 생성하고
if (instance == null)
{
instance = new GameObject(typeof(T).ToString(), typeof(T)).GetComponent<T>();
// Unity Scene 전환 시 해제되는 것을 막음
DontDestroyOnLoad(instance.gameObject);
}
// 있다면 만들어진 객체 반환
return instance;
}
}
}
protected virtual void OnDestroy()
{
lock (mutex)
instance = null;
}
protected virtual void OnApplicationQuit()
{
lock (mutex)
{
instance = null;
isDestroy = true;
}
}
}
|
위 템플릿 코드를 이용하여 싱글톤 패턴을 쉽게 생성할 수 있습니다! 🚀
템플릿 코드 사용 방법#
위 코드를 유니티 프로젝트에 추가한 후 사용합니다.
어떤 변수의 값이 변경 된다면 미리 등록해둔 콜백을 실행하는 EventManager
를 만든다고 가정한다면, 우선 Monobehaviour Script 파일을 생성해줍니다!
스크립트를 열면 기본적으로 MonoBehaviour
가 상속된 클래스를 만드는데 이 때 MonoBehaviour
대신 위에서 만든 템플릿을 상속 받게 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| using System;
using UnityEngine;
public class EventManager : TemplateManager<EventManager> // 템플릿 클래스 사용!
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void AddListener(Action<object> callback)
{
Debug.Log("싱글턴으로 만들어진 객체에서 쓰여진 로그!");
callback?.Invoke("Variable");
}
}
|
인스턴스 가져오기#
위 객체를 이용하고 싶다면 Instance
를 불러서 이욯하면 됩니다. 인스턴스가 생성되지 않았다면 만들어서, 이미 생성되어 있다면 생성된 객체를 반환해 줄테니까요! 👍
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class TitleCanvas : MonoBehaviour
{
public Button startButton;
private void Awake()
{
startButton.onClick.AddListener(() =>
{
SceneManager.LoadScene("ResponseScene");
});
// EvenetManager 함수 호출
EventManager.Instance.AddListener((obj) =>
{
// something;
});
}
}
|