반응형
ServiceLocator
서비스나 컴포넌트를 전역적으로 접근할 수 있게 해주는 디자인 패턴
구현 방법
1. 서비스로케이터 클래스
public class ServiceLocator
{
private static ServiceLocator instance;
private Dictionary<Type, object> services;
public static ServiceLocator Instance
{
get
{
if (instance == null)
{
instance = new ServiceLocator();
}
return instance;
}
}
private ServiceLocator()
{
services = new Dictionary<Type, object>();
}
public void RegisterService<T>(T service)
{
Type type = typeof(T);
if (services.ContainsKey(type))
{
Debug.LogWarning($"Service of type {type} is already registered!");
return;
}
services[type] = service;
}
public T GetService<T>() where T : class
{
Type type = typeof(T);
if (!services.ContainsKey(type))
{
Debug.LogError($"Service of type {type} not found!");
return null;
}
return services[type] as T;
}
public void UnregisterService<T>()
{
Type type = typeof(T);
if (services.ContainsKey(type))
{
services.Remove(type);
}
}
}
2. 서비스 인터페이스
public interface IScoreService
{
int GetScore();
void AddScore(int amount);
}
// 실제 서비스 구현
public class ScoreService : IScoreService
{
private int currentScore = 0;
public int GetScore() => currentScore;
public void AddScore(int amount) => currentScore += amount;
}
3. 사용 예시
public class GameManager : MonoBehaviour
{
void Start()
{
// 서비스 등록
ServiceLocator.Instance.RegisterService<IScoreService>(new ScoreService());
}
void UseService()
{
// 서비스 사용
var scoreService = ServiceLocator.Instance.GetService<IScoreService>();
scoreService.AddScore(100);
Debug.Log($"Current Score: {scoreService.GetScore()}");
}
}
핵심개념
- 서비스 로케이터는 애플리케이션 전체에서 필요한 서비스들을 중앙에서 관리하고 제공하는 패턴입니다
- 싱글톤 패턴을 기반으로 하여 전역적인 접근점을 제공합니다
- 인터페이스를 통한 느슨한 결합을 지향합니다
사용목적
- 서비스 의존성을 중앙에서 관리하여 코드 유지보수성 향상
- 런타임에 서비스 구현체를 유연하게 교체 가능
- 테스트 용이성 확보 (Mock 객체 사용 가능)
- 컴포넌트 간 직접적인 참조 없이 통신 가능
사용사례 및 예시코드
공통으로 사용할 서비스로케이터
public class ServiceLocator
{
private static ServiceLocator instance;
private Dictionary<Type, object> services = new Dictionary<Type, object>();
public static ServiceLocator Instance => instance ??= new ServiceLocator();
public void RegisterService<T>(T service) => services[typeof(T)] = service;
public T GetService<T>() where T : class
{
if (services.TryGetValue(typeof(T), out object service))
return service as T;
throw new Exception($"Service {typeof(T).Name} not found!");
}
}
1.게임 시스템관리
public interface IGameSystem
{
void StartGame();
void SaveGame();
int GetScore();
void AddScore(int points);
}
public class GameSystem : IGameSystem
{
private int currentScore = 0;
public void StartGame()
{
currentScore = 0;
Debug.Log("Game Started!");
}
public void SaveGame()
{
PlayerPrefs.SetInt("Score", currentScore);
Debug.Log("Game Saved!");
}
public int GetScore() => currentScore;
public void AddScore(int points)
{
currentScore += points;
Debug.Log($"Score updated: {currentScore}");
}
}
오디오시스템
public interface IAudioSystem
{
void PlayBGM(string trackName);
void PlaySFX(string sfxName);
void SetVolume(float volume);
}
public class AudioSystem : IAudioSystem
{
private Dictionary<string, AudioClip> audioClips = new Dictionary<string, AudioClip>();
private float masterVolume = 1.0f;
public void PlayBGM(string trackName)
{
Debug.Log($"Playing BGM: {trackName}");
// BGM 재생 로직
}
public void PlaySFX(string sfxName)
{
Debug.Log($"Playing SFX: {sfxName}");
// 효과음 재생 로직
}
public void SetVolume(float volume)
{
masterVolume = Mathf.Clamp01(volume);
Debug.Log($"Volume set to: {masterVolume}");
}
}
UI관리
public interface IUISystem
{
void ShowScreen(string screenName);
void ShowPopup(string popupName);
void HidePopup(string popupName);
}
public class UISystem : IUISystem
{
private Dictionary<string, GameObject> screens = new Dictionary<string, GameObject>();
private Stack<GameObject> activePopups = new Stack<GameObject>();
public void ShowScreen(string screenName)
{
Debug.Log($"Showing screen: {screenName}");
// 화면 전환 로직
}
public void ShowPopup(string popupName)
{
Debug.Log($"Showing popup: {popupName}");
// 팝업 표시 로직
}
public void HidePopup(string popupName)
{
Debug.Log($"Hiding popup: {popupName}");
// 팝업 숨김 로직
}
}
네트워크 통신
public interface INetworkSystem
{
void Connect(string serverUrl);
void SendData(string endpoint, string data);
void Disconnect();
}
public class NetworkSystem : INetworkSystem
{
private bool isConnected = false;
public void Connect(string serverUrl)
{
isConnected = true;
Debug.Log($"Connected to server: {serverUrl}");
}
public void SendData(string endpoint, string data)
{
if (!isConnected)
{
Debug.LogError("Not connected to server!");
return;
}
Debug.Log($"Sending data to {endpoint}: {data}");
}
public void Disconnect()
{
isConnected = false;
Debug.Log("Disconnected from server");
}
}
게임매니저 ( 실행부 )
public class GameManager : MonoBehaviour
{
private void Start()
{
// 모든 서비스 등록
ServiceLocator.Instance.RegisterService<IGameSystem>(new GameSystem());
ServiceLocator.Instance.RegisterService<IAudioSystem>(new AudioSystem());
ServiceLocator.Instance.RegisterService<IUISystem>(new UISystem());
ServiceLocator.Instance.RegisterService<INetworkSystem>(new NetworkSystem());
// 게임 시작
InitializeGame();
}
private void InitializeGame()
{
// 게임 시스템 초기화
var gameSystem = ServiceLocator.Instance.GetService<IGameSystem>();
gameSystem.StartGame();
// 오디오 시스템 설정
var audioSystem = ServiceLocator.Instance.GetService<IAudioSystem>();
audioSystem.PlayBGM("MainTheme");
audioSystem.SetVolume(0.8f);
// UI 초기화
var uiSystem = ServiceLocator.Instance.GetService<IUISystem>();
uiSystem.ShowScreen("MainMenu");
// 네트워크 연결
var networkSystem = ServiceLocator.Instance.GetService<INetworkSystem>();
networkSystem.Connect("game.server.com");
}
// 게임 플레이 예시
private void OnPlayerScore(int points)
{
var gameSystem = ServiceLocator.Instance.GetService<IGameSystem>();
gameSystem.AddScore(points);
var audioSystem = ServiceLocator.Instance.GetService<IAudioSystem>();
audioSystem.PlaySFX("ScoreSound");
if (points > 100)
{
var uiSystem = ServiceLocator.Instance.GetService<IUISystem>();
uiSystem.ShowPopup("HighScorePopup");
var networkSystem = ServiceLocator.Instance.GetService<INetworkSystem>();
networkSystem.SendData("scores/submit", gameSystem.GetScore().ToString());
}
}
}
결론
장점
- 전역적인 접근성 - 어디서든 서비스에 접근 가능
- 의존성 관리 용이
- 서비스 교체가 쉬움 (인터페이스 기반)
- 테스트 용이성 (Mock 객체로 쉽게 교체 가능)
단점
- 전역 상태를 만들어 코드의 결합도가 높아질 수 있음
- 서비스 의존관계가 명시적이지 않음
- 싱글톤 패턴의 단점을 일부 공유
각 시스템들은 ServiceLocator를 통해 쉽게 접근하고 관리할 수 있으며,
독립적으로 동작하면서도 필요할 때 서로 협력할 수 있게 만든다
반응형
'유니티 > 디자인패턴' 카테고리의 다른 글
[Unity] 유니티 C#) 다양한 클래스 유형 (0) | 2025.01.24 |
---|---|
[Unity] 유니티 C#) Facade 패턴 (0) | 2024.12.16 |
[Unity] 유니티 C#) Adapter 패턴 (0) | 2024.12.13 |
[Unity] 유니티 C#) SpatialPartition패턴 (0) | 2024.12.12 |
[Unity] 유니티 C#) Decorator 패턴 (0) | 2024.12.10 |