[게임 프로그래밍 패턴] Chapter6 싱글턴

Jangmanbo·2023년 8월 30일
0

싱글턴 패턴

  • 오직 한 개의 클래스 인스턴스만 갖도록 보장
    • 파일 시스템 api의 경우 비동기로 동작해야 한다. 즉 여러 작업이 동시에 진행될 수 있고 이 작업들을 다 파악해서 서로 간섭하지 못하게 해야 한다. 이를 위해서는 하나의 인스턴스 내에서만 작업이 진행되어야 한다.
  • 전역 접근점을 제공
    • 파일 시스템은 어느 시스템에서라도 접근 가능해야 한다. 이를 위해 싱글턴은 전역에서 접근할 수 있는 메서드를 제공한다.

싱글턴을 사용하는 이유

  • 한 번도 사용하지 않는다면 아예 인스턴스를 생성하지 않는다.
  • 런타임에 초기화된다.
    • 최대한 늦게 초기화되어 초기화될 시점에 클래스가 필요로 하는 정보들이 준비되어 있다.
  • 싱글턴을 상속할 수 있다.
    • 만약 파일 시스템 래퍼가 크로스 플랫폼을 지원하려면 추상 인터페이스를 만들고 플랫폼마다 구체 클래스를 만들면 된다.

싱글턴(전역 변수)의 문제점

  • 전역 변수는 코드를 이해하기 어렵게 한다.
  • 전역 변수는 커플링을 조장한다.
    • 전역으로 인스턴스에 접근 가능하므로 서로 디커플링되어야 하는 시스템이 쉽게 커플링될 수 있다.
  • 전역 변수는 멀티스레딩 같은 동시성 프로그래밍에 알맞지 않다.
    • 전역 변수는 모든 스레드가 수정할 수 있는 메모리 영역이다. 교착 상태, 경쟁 상태 등 스레드 동기화 버그가 생기기 쉽다.
  • 싱글턴을 다시 인스턴스를 여러 개 만들 수 있게 하려면 클래스와 클래스를 사용하는 코드를 전부 찾아 바꿔야 한다.
  • 게으른 초기화는 제어할 수 없다.
    • 초기화에 오래 걸리거나 메모리 단편화를 막기 위해서는 적절한 초기화 시점을 찾아 초기화 시점을 제어해야 한다. >> 해결 : 정적 인스턴스 사용 (but 다형성 사용 X, 메모리 해제 불가)

대안

애초에 싱글턴이 필요한지 생각해보기

객체가 스스로를 챙기게 하는 게 OOP다

오직 한 개의 클래스 인스턴스만 갖도록 보장하기

전역 접근 없이 클래스 인스턴스만 한 개로 보장하는 방법

class FileSystem {
public:
	FileSystem() {
    	assert(!instantiated_);
        instantiated_ = true;
    }
    ~FileSystem() {
    	instantiated_ = false;
    }
   
  private:
  	static bool instantiated_;
  };
  
  bool FileSystem::instantiated_ = false;

인스턴스에 쉽게 접근하기

변수는 최대한 적은 범위로 노출하는 게 일반적으로 좋다. 괜히 싱글턴 객체로 바꾸려하지 말고 객체에 접근 할 수 있는 다른 방법을 사용해보자.

  1. 넘겨주기 : 객체를 필요로 하는 함수에 인수로 넘겨주자
  2. 상위 클래스로부터 얻기
  3. 이미 전역인 객체로부터 얻기 : Log, FileSystem 같은 클래스를 싱글턴으로 만드는 대신 싱글턴인 Game 클래스를 통해 접근하자 (단, Game클래스에 커플링된다는 단점이 있음)
  4. 서비스 중개자로부터 얻기 : 여러 객체에 대한 전역 접근을 제공하는 용도로만 사용하는 클래스 정의하기

0개의 댓글