728x90
1. 서비스 중개자 패턴 정의
- 서비스를 구현한 구체 클래스는 숨긴 채로 어디에서나 서비스에 접근할 수 있게 하는 패턴
2. 서비스 중개자 패턴 구현
// 오디오 서비스가 제공할 인터페이스.
class Audio
{
public:
virtual ~Audio() {}
virtual void PlaySound( int InSoundId ) = 0;
virtual void StopSound( int InSoundId ) = 0;
virtual void StopAllSounds() = 0;
};
// 오디오 서비스
class ConsoleAudio : public Audio
{
virtual void PlaySound( int InSoundId )
{
// 콘솔의 오디오 API를 이용해 사운드를 출력한다.
}
virtual void StopSound( int InSoundId )
{
// 콘솔의 오디오 API를 이용해 사운드를 중지한다.
}
virtual void StopAllSounds()
{
// 콘솔의 오디오 API를 이용해 모든 사운드를 중지한다.
}
};
// 서비스 중개자
class Locator
{
private:
static Audio* Service;
public:
// 중개 역할을 하는 GetAudio() 함수
static Audio* GetAudio() { return Service; }
static void Provide( Audio* InService ) { Service = InService; }
};
int main()
{
// Locator가 오디오 서비스를 등록하는 방법
ConsoleAudio* consoleAudio = new ConsoleAudio();
Locator::Provide( consoleAudio );
// 중개자를 통해 Audio 인스턴스를 반환받아 사용
Audio* audio = Locator::GetAudio();
audio->PlaySound( SOUND_1 );
}
- 정적 함수인 GetAudio()가 중개 역할을 한다.
- 어디에서나 부를 수 있는 GetAudio() 함수는 Audio 인스턴스를 반환해 사용할 수 있도록 한다.
- PlaySound()를 호출하는 쪽에서는 Audio라는 추상 인터페이스만 알 뿐, ConsoleAudio라는 구체 클래스에 대해서는 전혀 모른다는 게 핵심이다.
- Locator 클래스와 서비스 제공자의 구체 클래스와는 커플링 되지 않는다.
- 어떤 구체 클래스가 실제로 사용되는지는 서비스를 제공하는 초기화 코드에서만 알 수 있다.
3. 널 객체 패턴 구현
// 널 객체 디자인 패턴
class NullAudio : public Audio
{
public:
virtual void PlaySound( int InSoundId ) { /*아무것도 하지 않는다.*/ }
virtual void StopSound( int InSoundId ) { /*아무것도 하지 않는다.*/ }
virtual void StopAllSounds() { /*아무것도 하지 않는다.*/ }
};
// 중개자
class Locator
{
private:
static Audio* Service;
static NullAudio NullService;
public:
// 널 서비스로 초기화
static void Initialize()
{
Service = &NullService;
}
// 중개 역할을 하는 GetAudio() 함수
static Audio* GetAudio() { return Service; }
static void Provide( Audio* InService )
{
if ( Service == nullptr )
{
// 널 서비스로 돌려놓는다.
Service = &NullService;
}
else
{
Service = InService;
}
Service = InService;
}
};
- 서비스 제공자가 서비스를 등록하기 전에 서비스를 사용하려고 하면, NULL을 반환해 크래시 위험이 있다.
- 객체를 찾지 못하거나 만들지 못해 NULL을 반환해야 할 때, 대신 같은 인터페이스를 구현한 특수한 객체를 반환한다.
- 아무런 구현이 되어 있지 않지만, 객체를 받는 쪽에서는 '진짜' 객체를 받은 것처럼 안전하게 작업을 할 수 있다.
4. 데커레이터 패턴 구현
// 데커레이터 패턴
class LoggedAudio : public Audio
{
private:
Audio& Wrapped;
private:
void Log( cosnt std::string& InMessage )
{
// 로그
}
public:
LoggedAudio( AUdio& InWrapped ) : Wrapped( InWrapped ) {}
virtual void PlaySound( int InSoundId )
{
log ( "사운드 출력" );
Wrapped.PlaySound( InSoundId );
}
virtual void StopSound( int InSoundId )
{
log ( "사운드 중지" );
Wrapped.StopSound( InSoundId );
}
virtual void StopAllSounds()
{
log ( "모든 사운드 중지" );
Wrapped.StopAllSounds();
}
};
int main()
{
// 기존 서비스를 데커레이트한다.
Audio* service = new LoggedAudio( Locator::GetAudio() );
// 이 값으로 바꿔치기한다.
Locator::Provide( service );
}
- 조건적으로 로그를 남기고 싶은 시스템이 서비스로 노출되어 있다면 데커레이터 패턴 ( 장식자 패턴 )으로 해결이 가능하다.
- LoggedAudio 클래스는 다른 오디오 서비스 제공자를 래핑하는 동시에, 같은 인터페이스를 상속받는다.
- 실제 기능 요청은 내부에 있는 서비스에 전달하고, 대신 사운드가 호출될 때마다 로그를 남긴다.
반응형
'Design Pattern > 게임 프로그래밍 패턴' 카테고리의 다른 글
| [Design Pattern] 더티 플래그 패턴 (0) | 2022.08.18 |
|---|---|
| [Design Pattern] 데이터 지역성 패턴 (0) | 2022.08.16 |
| [Design Pattern] 이벤트 큐 패턴 (0) | 2022.08.05 |
| [Design Pattern] 컴포넌트 패턴 (0) | 2022.08.05 |
| [Design Pattern] 하위 클래스 샌드박스 패턴 (0) | 2022.08.02 |