Zenject Example ~さよならManager編~

1d1580fb0945b0ffadff18e28bead3c5?s=47 いも
August 26, 2019

Zenject Example ~さよならManager編~

Roppongi.unity #04 で発表した資料です

1d1580fb0945b0ffadff18e28bead3c5?s=128

いも

August 26, 2019
Tweet

Transcript

  1. 3.

    どこのご家庭にもあるMasterDataManager public class MasterDataManager : SingletonMonoBehaviour<MasterDataManager> { public List<PlayerData> Players

    { get; private set; } public List<EnemyData> Enemies { get; private set; } public List<ItemData> Items { get; private set; } private CsvLoader _provider; public PlayerData FindById(int id) => Players.Find(p => p.id == id); void Start() { Players = _provider.LoadAll<PlayerData>("path/to/players"); Enemies = _provider.LoadAll<EnemyData>("path/to/enemies"); Items = _provider.LoadAll<ItemData>("path/to/items"); } } 2019/08/26 Roppongi.unity #04 3
  2. 7.

    まずはテスト namespace Tests { public class MasterDataManagerTest { private MasterDataManager

    _manager; [UnityTest] public IEnumerator FindById_Success() { _manager = new GameObject().AddComponent<MasterDataManager>(); yield return new WaitForEndOfFrame(); var playerData = _manager.FindById(1); Assert.AreEqual("Foo", playerData.name); } } } 2019/08/26 Roppongi.unity #04 7
  3. 12.

    呼ぶ側が書き直せる public class FooBehaviour { public void Foo(){ var player

    = MasterDataManager.Instance.FindById(1); } } ↓ public class FooBehaviour { [Inject] private MasterDataManager manager; public void Foo(){ var player = manager.FindById(1); } } 2019/08/26 Roppongi.unity #04 12
  4. 13.

    全箇所移行完了したらMonoBehaviour に書き直す public class MasterDataManager : MonoBehaviour { public List<PlayerData>

    Players { get; private set; } public List<EnemyData> Enemies { get; private set; } public List<ItemData> Items { get; private set; } private CsvLoader _provider; public PlayerData FindById(int id) => Players.Find(p => p.id == id); void Start() { Players = _provider.LoadAll<PlayerData>("path/to/players"); Enemies = _provider.LoadAll<EnemyData>("path/to/enemies"); Items = _provider.LoadAll<ItemData>("path/to/items"); } } 2019/08/26 Roppongi.unity #04 13
  5. 16.

    IInitializable を実装してみよう public class MasterDataManager : MonoBehaviour, IInitializable { public

    List<PlayerData> Players { get; private set; } public List<EnemyData> Enemies { get; private set; } public List<ItemData> Items { get; private set; } private CsvLoader _provider; public PlayerData FindById(int id) => Players.Find(p => p.id == id); public void Initialize(){ Players = _provider.LoadAll<PlayerData>("path/to/players"); Enemies = _provider.LoadAll<EnemyData>("path/to/enemies"); Items = _provider.LoadAll<ItemData>("path/to/items"); } } 2019/08/26 Roppongi.unity #04 16
  6. 18.

    不要になったのでMonoBehaviour をやめよう public class MasterDataManager : IInitializable { public List<PlayerData>

    Players { get; private set; } public List<EnemyData> Enemies { get; private set; } public List<ItemData> Items { get; private set; } private CsvLoader _provider; public PlayerData FindById(int id) => Players.Find(p => p.id == id); public void Initialize(){ Players = _provider.LoadAll<PlayerData>("path/to/players"); Enemies = _provider.LoadAll<EnemyData>("path/to/enemies"); Items = _provider.LoadAll<ItemData>("path/to/items"); } } 2019/08/26 Roppongi.unity #04 18
  7. 19.

    MonoBehaviour じゃなくなったのでInstaller を書こう public class MasterDataInstaller : MonoInstaller { public

    override void InstallBindings() { Container.Bind<MasterDataManager>().AsSingle(); } } 2019/08/26 Roppongi.unity #04 19
  8. 20.

    テストも少し書き直そう namespace Tests { public class MasterDataManagerTest { private MasterDataManager

    _manager; // MonoBehaviour じゃないのでEditTest で十分 [Test] public void FindById_Success() { _manager = new MasterDataManager(); _manager.Initialize(); var playerData = _manager.FindById(1); Assert.AreEqual("Foo", playerData.name); } } } 2019/08/26 Roppongi.unity #04 20
  9. 22.

    今一度MasterDataManaer の立ち位置を考える なぜSingleton なのか => DI でOK なぜ複数の種類のデータを持ってたのか? => 直接Inject

    できるなら 纏める必要はない なぜMasterDataManager という名前がついてたのか? => 纏める必 要ないなら不要では? 2019/08/26 Roppongi.unity #04 22
  10. 23.

    データ持ってるクラスを独立 public class PlayerDataRepository { private readonly List<PlayerData> _resources; public

    PlayerDataRepository(IResourceLoadProvider _provider) { _resources = _provider.LoadAll<PlayerData>("path/to/players"); } public PlayerData FindById(int id) => _resources.Find(p => p.id == id); } public class MasterDataInstaller : MonoInstaller { public override void InstallBindings() { Container.BindInterfacesAndSelfTo<MasterDataManager>().AsSingle(); Container.BindInterfacesAndSelfTo<PlayerDataRepository>().AsSingle(); Container.Bind<IResourceLoadProvider>().To<CsvLoader>().AsSingle(); } } 2019/08/26 Roppongi.unity #04 23
  11. 24.

    PlayerDataRepository だけ差し替えて動作は変えない public class MasterDataManager : IInitializable { public List<EnemyData>

    Enemies { get; private set; } public List<ItemData> Items { get; private set; } [Inject] private IResourceLoadProvider _provider; [Inject] private PlayerDataRepository _playerDataRepository; public PlayerData FindById(int id) => _playerDataRepository.FindById(id); public void Initialize() { Enemies = _provider.LoadAll<EnemyData>("path/to/enemies"); Items = _provider.LoadAll<ItemData>("path/to/items"); } } 2019/08/26 Roppongi.unity #04 24
  12. 26.

    Test もZenject 対応 public class MasterDataManagerTest : ZenjectUnitTestFixture { public

    class MockLoader : IResourceLoadProvider { public List<T> LoadAll<T>(string path) => new List<T>(/* なんかいい感じ生成 */); } private MasterDataManager _manager; [Test] public void FindById_Success() { Container.Bind<MasterDataManager>().AsSingle(); Container.BindInterfacesTo<MockLoader>().AsSingle(); Container.Bind<PlayerDataRepository>().AsSingle(); _manager = Container.Resolve<MasterDataManager>(); _manager.Initialize(); var playerData = _manager.FindById(1); Assert.AreEqual("Foo", playerData.name); } } 2019/08/26 Roppongi.unity #04 26