Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

게임 프로그래밍

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

프로그래밍/디자인 패턴

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

Junwe 2020. 1. 10. 17:37

싱글턴은 오직 한개의 클래스 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공한다.(Gof의 디자인 패턴)

 

사실 싱글턴은 가장 쉽게 남용되는 디자인 패턴일 것이다. 

 

우선 싱글턴 패턴에 대해서 알아보자.

 

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

인스턴스가 여러 개면 제대로 작동하지 않는 상황이 종종 있다. 간단하게 파일 시스템을 예로 들자면 파일 작업은 완료하는데 시간이 걸리기 때문에 비동기로 동작하게 되어야 한다. 쉽게 생각해서 한쪽에서는 파일을 생성하고 있는데 다른쪽에서 삭제가 이루어지고 있다면 문제가 있을 것이다. 이러한 상황은 싱글턴으로 만들면 클래스가 인스턴스를 하나만 가지도록 컴파일 단계에서 강제할수 있어 방지 할수있다.

 

2. 전역 접근점을 제공

싱글턴 패턴은 모든곳에서 접근할 수 있도록 하게 한다.

 

그렇다면 싱글턴에 장점은?

1. 한번도 사용하지 않는다면 인스턴스를 생성하지 않는다.

2. 런타임에 초기화 된다.

3. 싱글턴을 상속할 수 있다.

 

왜 문제인가?

싱글턴 패턴 자체에는 문제가 없다. 하지만 필요하지 않는 상황에서까지 싱글턴 패턴을 사용하는것이 문제가 되는것이다.

 

1. 싱글턴은 전역 변수이다.

전역 변수는 어디서든 접근이 가능하다. 그러므로 문제가 생길때가 있다. 예를 들어 SomeClass::getSomGlobalData()라는 코드가 있다고 한다면 이 코드에 문제가 생겼을때 코드에 있는 모든 getGlobalData를 찾아야한다. 모든 코드에서 확인해보는 작업이 쉽지 않을것이다.

 

또한 전혁 변수는 커플링을 조장한다.

 

어떻게 해결할까?

싱글턴은 두가지의 이유로 사용한다. 앞서 얘기했던 인스턴스를 하나만 사용하게 하는것과 전역 접근. 하지만 싱글턴을 사용할때 둘중 하나만 사용하고 싶은데도 두개의 문제를 가지고 가는것이 아닐까?

 

우선 싱글턴이 꼭 필요한가를 생각해보자.

많은 게임 프로그래머들이 MonsterManager, SoundManager, ParticleManager 등 관리자 클래스를 자주 만든다. 물론 관리자 클래스가 필요할때도 있겠지만 관리자 클래스가 하는 일을 원래 클래스(Monster, Sound,Paricle)에서 해도 상관없지 않을까 하는 생각을 다시 한번 해보자.

 

그렇다면 첫번째 문제를 해결해보자

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

생성자에서 assert를 사용해서 객체가 만들어졌는지 확인한다.

 

간단한 예를 들자면

class FileSystem{

public:

         FileSystem(){

           assert(instantiated_)

          instantiated_ = true;

         }

         !FileSystem(){

          instantiated_ = false;

             }

private:

       static bool instantiated_;

}

이런 식이다. instantiated_가 true면은 더 이상 생성하지 않게 만드는것이다.

 

2. 접근을 쉽게 하기

접근을 쉽게 한다는것은 앞서 이야기 했던 것 처럼 코드를 복잡하게 만든다. 괜히 private, public등 접근제어지시자가 있는게 아닐것이다. 그러므로 싱글턴 패턴처럼 여기저기 쉽게 접근을 하는것이 아닌 다른 접근 방법을 생각해보자.

 

넘겨주기

가장 좋은 방법은 객체를 필요로 하는 함수에 인수로 넘겨주는것이다. 이는 귀찮을수 있지만 좋은 방법일것이다.

하지만 어떤 객체는 메서드 시그니처에 포함되자 않는다. AI에서 LOG 객체를 인수로 받는것은 조금 이상할수 있다.

 

상위 클래스로부터 얻기

모든 Object들이 GameObject를 상속받는다고 하면 많은 하위 클래스들은 GameObject에 있는 데이터에 접근을 할수 있을것이다. 이 점을 활용해서 상위 클래스에 접근 해야하는 데이터를 넣고 사용할 수 있을것이다.

 

이미 전역인 객첼 부터 얻기

 

여러가지 싱글턴을 만드는 대신 GameManager, Wolrd 같은 싱글턴을 하나만 만들고 이 안에 FileSystem,AudioPlayer, MonsterCreater 같은 애들을 넣는것이다. 그러면 Game::Instance().getAudioPlayer().Play() 이렇게 접근이 가능할 것이다.이렇게 된다면 Game 인스턴스가 나중에 여러개 지원하게 된다고 하더라도 안에 있는 데이터는 변경하지 않아도 될것이다.

 

이는 Game 클래스에 디커플링 된다는 문제가 있긴하지만 싱글턴을 여러개 만드는것보다는 나은 방법일것이고, Game 클래스 안에 있는 객체를 바로 사용하는것이 아닌 초기화에서 한번만 가져온뒤 사용하는 방법으로 예방이 가능하다.

Comments