싱글턴 패턴

정선호·2023년 5월 6일
0

Design Patterns

목록 보기
5/24

관련 영상

싱글턴 패턴

위키피디아-싱글턴 패턴
설명 및 스도코드

  • 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.

싱글턴의 구조

  • 싱글턴 클래스
    • 정적 메서드 getInstance를 선언, 이 메서드는 자체 클래스의 동일한 인스턴스 반환
    • 싱글턴의 생성자는 항상 클라이언트 코드에서부터 숨겨져야 함

싱글턴의 문제점

  1. 클래스에 인스턴스가 하나만 있도록 한다.
    • 클래스에 있는 인스턴스 수를 제어하려는 가장 일반적인 이유는 일부 공유 리소스에 대한 접근을 제어하기 위함
    • 객체를 생성했지만 잠시 후 새 객체를 생성하기로 했다고 가정했을 때, 새 객체를 생성하는 대신 이미 만든 객체를 받게 된다. 물론 생성자 호출은 특성상 반드시 새 객체를 반환해야 하므로 위 행동은 일반 생성자로 구현할 수 없다.
  2. 해당 인스턴스에 대한 전역 접근 지점을 제공
    • 필수 객체들을 저장하기 위해 전역 변수들을 정의했을 때 이 변수들을 사용하면 매우 편리할지는 몰라도, 모든 코드가 잠재적으로 해당 변수의 내용을 덮어쓸 수 있고 그로 인해 앱에 오류가 발생해 충돌할 수 있으므로 그리 안전한 방법은 아니다.
  • 싱글턴 패턴은 스파게티 코드를 만들어 유닛 테스트를 어렵게 할 가능성이 높게 된다

싱글턴 패턴의 적용

  • 싱글턴 패턴은 프로그램의 클래스에 모든 클라이언트가 사용할 수 있는 단일 인스턴스만 있어야 할 떄 사용
    • 싱글턴 패턴은 특별 생성 메서드를 제외하고 클래스의 객체들을 생성할 수 있는 모든 다른 수단들을 비활성화 한다.
  • 전역 변수들을 더 엄격하게 제어해야 할 때 사용
    • 전역 변수들과 달리 싱글턴 패턴은 클래스의 인스턴스가 하나만 있도록 보장해준다
  • 싱글턴 패턴은 단일 책임 원칙을 엄격히 따라 싱글턴 클래스의 비대화를 방지한다

다른 패턴과의 관계

  • 퍼사드 패턴의 클래스는 종종 싱글턴으로 변환될 수 있음
  • 객체들의 공유된 상태를 단 하나의 플라이웨이트 객체로 즐일 수 있으면 플라이웨이트는 싱글턴과 유사해질 수 있음 그러나 둘에게는 두 가지의 근본적인 차이점이 존재
    • 싱글턴은 인스턴스가 하나만 있어야 하지만 플라이웨이트는 여러 고유한 상태를 가진 여러 인스턴스를 포함할 수 있음
    • 싱글턴 객체는 변할 수 있지만 플라이웨이트 객체들은 변할 수 없음
  • 추상 팩토리들, 빌더들, 프로토타입들은 모두 싱글턴으로 구현 가능

유니티에서의 싱글턴 패턴

  • MonoBehaviour을 상속받아 디폴트 생성자를 막음으로써 싱글턴의 문제점 1번을 해결한다
class Singleton : MonoBehaviour
{
    public static Singleton Instance { get; private set; }

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

유니티 싱글턴 오디오 매니저

  • 참고 영상
  • 오디오 매니저
    • 배경음 혹은 효과음을 출력해주는 오디오 매니저는 하나의 게임 클라이언트에 하나만 필요하므로 싱글턴으로 구현할 수 있다.
    • 해당 코드에서는 setterprivate으로 하여 외부의 임의적인 값 변경을 차단하였다
/* 오디오 매니저 */
public class AudioManager : MonoBehaviour
{
    public static AudioManager Instance { get; private set; }

    private void Awake()
    {
        Instance = this;
        _audioSource = GetComponent<AudioSource>();
    }
    
    private Queue<AudioSource> _audioSources = new Queue<AudioSources>();
    private AudioSource _audioSource;
    
    public void PlayClipAtPoint(AudioClip clip, Vector3 point)
    {
    	// 소리와 소리나는 방향을 이용해 소리 구현
    }
    
    // 활성화되면 자식 오브젝트에 오디오 소스 컴포넌트를 생성한 후 큐에 저장
    private void OnEnable()
    {
    	if (transform.childCount > 0)
        	return;
        
        for (int i = 0; i < 10; i++)
        {
        	var audioSourceGameObject = new GameObject("AudioSource " + i);
            audioSourceGameObject.transform.SetParent(transform);
            var audioSource = AudioSourceGameObject.AddComponent<AudioSource>();
            _audioSources.Enqueue(audioSources);
        }
        
    }
}

유니티 제네릭 싱글턴 클래스

  • Monobehaviour를 상속하는 클래스들을 싱글턴으로 만들어주는 제네릭 클래스이다.
  • 이런게 있다 정도만 알면 충분
public class LazeInstantiatedSingleton<T> : MonoBehaviour
	where T : MonoBehaviour
{
	private static T _instance;
    
    public static T Instance
    {
    	get
        {
        	if (_instance == null)
           	{
            	_instance = GameObject.FindObjectOfType<T>();
                if (_instance == null
                {
                	_instance = new Gameobject().AddComponent<T>();
                }
            }
            return _instance;
        }
    }
}
profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

0개의 댓글