싱글톤 패턴
Project/Win32API로 던그리드 모작

싱글톤 패턴

Woon2World :: Programming & Art Life

 

 

https://jartlife.tistory.com/52

 

타이머 - 프레임 관리

게임의 동작 게임은 일정 시간 간격마다 사용자 입력을 처리하고 객체들을 업데이트한 뒤 객체들을 렌더링한다. 따라서 게임에서 타이머의 역할은 매우 중요하다. 게임의 거의 모든 기반이 타

jartlife.tistory.com

 

위 글에서 복잡한 디자인 패턴 없이 싱글톤을 구현했다.

위 글에서 사용한 방법이 훨씬 더 나은 방법이라 생각되지만, 이 글에서 구현한 싱글톤 패턴이 불가피할 상황이 있을지도 모르므로 글은 남겨둔다.

 


 

 

// singleton.h
 
#ifndef _singleton
#define _singleton
template <typename T>
class Singleton
{
public:
    static auto& getinst()
    {
        static T inst = no_constructor_call{};
        return inst;
    }
    Singleton(const Singleton&= delete;
    void operator=(const Singleton&= delete;
 
protected:
    struct no_constructor_call {};
    Singleton() {}
};
#endif
cs

 

 

싱글톤 패턴이란,

어떠한 클래스로 찍어낸 객체가 프로그램 내에서 유일하도록 보장하는 디자인패턴이다

단순히 전역 객체를 만드는 것만으로는 그 클래스로 만든 객체 갯수가 1개임을 보장할 수 없기에 사용한다

 

class의 static 멤버를 반환하는 static 함수 getinst를 두고

getinst 함수를 통해서만 객체를 얻는 것이 가능하도록 하면

static한 객체 단 한 개의 생성만 보장할 수 있다

 

클래스마다 개별로 싱글톤화하는 작업을 하면 조금 더 코드가 이해하긴 쉬우나

게임은 유일하게 존재해야 하는 객체들이 많은 프로그램 카테고리에 속한다

매번 싱글톤을 적용하면 타이핑이 늘어나므로, 싱글톤 베이스를 만들고 그것을 상속함으로써 싱글톤화 되도록 한다

 

 

 

다음을 활용한 테크닉이 쓰였다

  • CRTP 패턴
  • reverse protected 패턴 (내가 이름 붙였다)
  • 암시적 형변환
  • 팩토리 메서드 패턴

 

CRTP 패턴

실제로 싱글톤인 클래스 T를 만들 때에는 Singleton<T>를 상속해 구현한다

이 때 부모 클래스의 특수화에 자식 클래스가 쓰인다

 

reverse protected 패턴

부모 클래스의 protected 멤버를 자식 클래스는 이용 가능하나 외부에서는 이용하지 못하는 것처럼

자식 클래스의 public 멤버를 부모 클래스는 이용 가능하나 외부에서는 이용하지 못하기를 원할 때

자식 클래스의 public 멤버가 부모 클래스의 protected 멤버인 클래스를 "매개변수"로 받도록 하면 목적 달성이 가능하다

그 멤버는 사실상 public 멤버가 아니라 reverse protected 멤버가 된다

 

실제로 싱글톤인 클래스 T는 Singleton::no_constructor_call을 매개변수로 받는 생성자만 유일하게 둠으로써 외부 생성을 막을 수 있다 (컴파일조차 되지 않게 만드니 올바른 코드 작성 유도에 상당한 이점이 있다)

 

암시적 형변환

static T inst = no_constructor_call{}; 은 T에 no_constructor_call을 매개변수로 받는 생성자가 있을 때에만

no_constructor_call로부터 T로의 암시적 형변환이 이루어져 컴파일이 가능해진다

 

왜 굳이 암시적 형변환을 이용하는가? 단순히 디버깅 메시지가 보기 편하도록 만들기 위해서이다

static T inst(no_constructor_call{});

static T inst{no_constructor_call{}};

static T inst = no_constructor_call{};

 

팩토리 메서드 패턴

생성자는 아까 reverse protected 패턴을 통해서 외부 호출이 불가능하도록 만들었다

그런데 생성이 불가능하면 객체를 어떻게 얻는가?

Singleton에 담긴 getinst를 통해서 얻는다, Singleton 내에선 실제 싱글톤인 클래스 T를 생성할 수 있다(생성자가 reverse protected 이기 때문에), getinst는 T를 static하게 생성한 뒤 돌려주는 일종의 팩토리 메서드이다

 

 

 

다음 글에서 실제 구현된 싱글톤 클래스 BackBuffer를 볼 수 있다

https://jartlife.tistory.com/45

 

더블버퍼링

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {     HDC hDC;     PAINTSTRUCT ps;     // ...     switch (uMsg)     {     // .....

jartlife.tistory.com