Unityにおける Service Locator パターン解説資料
目次
1. はじめに
Service Locator パターンは、必要なサービス(依存オブジェクト)をグローバルに取得可能にする設計手法です。
Unityにおいては、シーンをまたいで共有される機能(サウンド、セーブ管理など)を動的に利用したい場合に有効です。
2. 特徴と利点・欠点
特徴
- グローバルなサービスアクセスポイント(Locator)を通じて、サービスを取得
- 利用側が依存関係を意識せずにサービスを取得できる
- 実装の差し替えが可能(モック化など)
利点
- コード上の依存関係を意識せずにサービスを呼び出せる
- シングルトンよりも柔軟に差し替えや管理ができる
欠点
- 依存関係が不明瞭になる(どのクラスが何に依存しているか分かりにくい)
- 単体テストが困難(サービスの差し替えが見えにくい)
- グローバル状態への依存リスクがある
3. Unityでの実装手順
3.1 サービスインターフェースの定義
public interface IAudioService
{
void PlaySound(string soundName);
}
3.2 実装クラスの作成
public class AudioService : IAudioService
{
public void PlaySound(string soundName)
{
Debug.Log($"[Audio] 再生: {soundName}");
// 実際のAudioSource再生処理など
}
}
3.3 ServiceLocator クラスの作成
using System;
using System.Collections.Generic;
public static class ServiceLocator
{
private static readonly Dictionary<Type, object> _services = new();
public static void Register<T>(T service)
{
_services[typeof(T)] = service;
}
public static T Get<T>()
{
return (T)_services[typeof(T)];
}
public static bool TryGet<T>(out T service)
{
if (_services.TryGetValue(typeof(T), out var instance))
{
service = (T)instance;
return true;
}
service = default;
return false;
}
}
3.4 利用側の実装例
public class GameInitializer : MonoBehaviour
{
private void Awake()
{
var audioService = new AudioService();
ServiceLocator.Register<IAudioService>(audioService);
}
}
public class Player : MonoBehaviour
{
private void Start()
{
var audio = ServiceLocator.Get<IAudioService>();
audio.PlaySound("Jump");
}
}
4. 使用時の注意点
観点 | 内容 |
---|---|
可読性 | コードから依存関係が見えにくくなる |
テスト性 | テスト時に依存の差し替えが困難になる |
グローバル依存 | 状態の共有や初期化タイミングが曖昧になりやすい |
5. 実践的な補足(Unity向け)
- ScriptableObjectを使ってサービスの定義をアセット化することで、差し替えや検証がしやすくなる
- サービス登録の初期化タイミングは、アプリ起動時のGameManagerやBootstrapperなどで統一すると安定する
- ログ、セーブデータ管理、リソース読み込みなどの共通機能に向いている
6. まとめ
Service Locator パターンは、Unityにおいて動的なサービス管理を実現する強力な手段です。ただし、過度な使用はコードの複雑化を招くため、用途を限定しつつ、テスト性や設計の明示性にも配慮することが重要です。
ディスカッション
コメント一覧
まだ、コメントがありません