[Unity Engine] 종합설계프로젝트2 유니티 엔진 공부 #2

신형석·2023년 3월 22일
0

게임 개발 일지

목록 보기
7/10

이번에 공부한 내용은 싱글톤 패턴(Singleton Pattern)이다. 모든 지식이 그렇듯, 처음 접했을 때 무슨 소린지 1도 이해가 가지 않았다. 처음부터 천천히 정리해보도록 하겠다.

싱글톤 패턴의 위키백과를 보면,

소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다.

이렇게 정리되어 있다. 여러 언어에 대한 코드와 함께 확인하고 싶다면 이곳을 참고하기 바란다.

저게 무슨 소리냐 하면, 클래스를 만들 때 단 하나의 인스턴스만을 만들고, 이에 대한 전역적인 접근을 허용한다는 뜻이다.

너무 헷갈리는 사람들을 위해, 우선 딴 길로 새서 클래스, 객체, 인스턴스에 대해 알아보도록 하자.


클래스, 객체, 인스턴스

클래스 : 객체를 만들기 위한 설계도와 같은 것
객체 : 클래스라는 설계도로 소프트웨어 세계에 구현할 대상
인스턴스 : 객체를 실제로 구현한 실체

간단하게 정리하면 이렇게 정리할 수 있다. 본인도 사실 공부를 진행하면서 굉장히 헷갈렸던 내용이기에, 주제가 싱글톤 패턴이지만 정리해보려고 한다.

클래스는 코드에서 우리가

public class Game (){

}

으로 적는 클래스가 맞다. 이러한 클래스를 가지고

Shooting_Game = Game();

으로 적는다면, 여기서 Shooting_Game은 객체가 되는 것이다.

인스턴스가 굉장히 헷갈릴텐데,

객체는 어떠한 대상이고 인스턴스는 실체라는데 대체 뭐가 다른거임?

이렇게 생각할 것이다. 인스턴스는, 특정 객체가 어떤 클래스의 객체인지에 대한 관계를 중점으로 설명한다고 한다. 그렇다면,
위의 코드에서 Shooting_Game 객체는 Game() 클래스인스턴스라고 할 수 있을 것이다.

클래스와 객체, 인스턴스에 대해 정리해보았다. 사실 본인도 구글 검색을 하면서 찾아보았지만, 확실하게 클래스는 이거다! 객체는 이거다! 라고 정리를 확실하게 해놓은 글을 찾기 힘들었다. 아주 얕은 지식으로 적은 글이므로, 지적이나 수정 요청이 있다면 다시 공부하고 수정하도록 하겠다.

이제 진짜로 싱글톤 패턴에 대해 알아보자.


싱글톤 패턴 (Singleton Pattern)

클래스, 객체, 인스턴스에 대한 정리가 끝났으니, 위에 정리한 내용을 확실하게 할 수 있을 것이다.

클래스를 만들 때 단 하나의 인스턴스만을 만들고, 이에 대한 전역적인 접근을 허용한다.

단 하나의 인스턴스를 만들어서, 다른 함수나 스크립트에서 사용할 수 있는 코드를 만든다고 생각하는 것이 편할 것이다. 코드를 보면서 설명하도록 하겠다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton : MonoBehaviour
{
	// 자기 자신의 instance를 선언한다. 보안을 확실하게 하기 위해 private를 사용한다. 
    private static Singleton instance = null;

    void Awake()
    {	
    	// instance 값이 null일 경우 (인스턴스가 만들어져 있지 않은 경우), 자기 자신을 넣어준다. 
        // 또한, 이 오브젝트는 Scene 전환이 되어도 사라지면 안 되기 때문에, DontDestroyOnLoad를 사용하여 삭제되지 않도록 한다. 
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(this.gameObject);
        }
        // Scene 전환이 되었는데, 다른 인스턴스가 있는 경우 인스턴스를 삭제하여 단 하나만 존재하게 한다. 
        else
        {
            Destroy(this.gameObject);
        }
    }
    // static을 사용하여, 전역에서 접근할 수 있게 만들어준다. 이 함수를 사용하면, 다른 스크립터에서도 Singleton의 instance에 접근할 수 있다. 
    public static Singleton getInstance
    {
        get
        {
            if (null == instance)
            {
                return null;
            }
            return instance;
        }
    }
	// Singleton에 구현되어 있는 함수 중 하나 (예시)
    public void Function()
    {
    
    }
}

주석으로 설명을 해놓았지만, 간단하게 설명을 적도록 하겠다.

우선,

private static Singleton instance = null;

private를 사용하여 보안을 챙기는 동시에 null을 넣어주며 초기화해준다.

void Awake()
{	
    if (instance == null)
    {
        instance = this;
        DontDestroyOnLoad(gameObject);
    }
    else
    {
        Destroy(this.gameObject);
    }
}

if문을 사용하여, instance에 null값이 들어있다면, 즉 아무런 값이 들어가있지 않다면 instance에 자기 자신을 넣어 instance를 하나 만들어준다. 그리고, DontDestroyOnLoad를 사용하여 Load하더라도 사라지지 않게 한다.
else문으로 들어갈 경우, 이는 Scene 전환을 하였는데 그 곳에 다른 instance가 있는 경우이다. Destroy를 사용하여 그런 instance를 삭제해준다.

public static Singleton getInstance
{
    get
    {
        if (null == instance)
        {
            return null;
        }
        return instance;
    }
}

함수를 static으로 설정하여, 다른 함수에서도 instance에 접근할 수 있도록 한다.

public void Function()
{

}

외부에서의 함수 사용을 위해 만든 함수의 예제이다. 이 함수를 사용하기 위해서는,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SingletonExample : MonoBehaviour
{
    private void Start()
    {
        Singleton.getInstance.Function();
    }
}

위와 같이

클래스 이름.static으로 설정한 함수 이름.함수

의 양식으로 외부에서 사용할 수 있다.

추가

함수를 추가해보고 실행하는 과정에서 약간의 어려움을 겪었기에 작성한다.

함수를 실행할 때, 빈 오브젝트 하나에 Singleton 스크립트를 넣고, 다른 오브젝트든 같은 오브젝트든 SingletonExample 스크립트를 넣어서 실행시키면 Function()이 실행되는 것을 알 수 있다. Function 함수가 실행되었음을 확인하기 위해,

public void Function()
{
    Debug.Log("Singleton 성공!");
}

이런 식으로 Singleton 스크립트의 Function 함수에 Debug.Log를 사용하여 문장을 출력하도록 하였다.


본인은 한 오브젝트에 모두 집어넣었다. 그 후 프로그램을 실행하면,

이런 식으로 Function 함수가 성공적으로 실행되는 것을 볼 수 있다. 밑의 다른 출력들은 이전에 공부한 스크립터블 오브젝트의 잔여물이다.

이런 간단한 것을 정리하는 이유는, 본인은 스크립트를 SingletonExample만 빈 오브젝트에 넣어서 실행해서 NullReferenceException 오류가 발생하였기 때문이다. Singleton 스크립트에 instance 생성 코드가 있는데, instance를 생성하지도 않고 ScriptableExample에서 getInstance로 Singleton에 접근하려고 해서 발생하는 오류였다. Singleton 스크립트에서도 Awake()가 있기 때문에 오브젝트에 넣어서 실행시켜줘야 한다는 사실을 잊어버린 것이었다.


이렇게 싱글톤 패턴에 대해 알아보았다. 싱글톤 패턴은 인스턴스를 단 하나만 생성함에 있어서 메모리의 이점을 가지면서, static을 사용하였기 때문에 전역변수와 같은 느낌으로 사용할 수 있다. 그러나, 코드 자체가 많이 필요하고, 테스트하기 어렵다 등등 여러 단점이 많이 존재한다.

0개의 댓글

관련 채용 정보