partialを用いたクラス設計
業務でpartialを使うことがあったのでメモ
そもそもpartialって何?
結論から言うと、partialはクラスの定義を複数のファイルに分割する時に使うらしい
例えばUnityでクラスを定義する時は、ソースファイル名に基づいて同名のクラスを
定義するがpartialを使うことで複数のソースファイルに同じクラスを定義できるとのこと
サンプルソース
SampleClass.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public partial class SampleClass : MonoBehaviour { private int aaa = 10; // Use this for initialization void Start () { this.Func(); } // Update is called once per frame void Update () { } }
SampleClassB.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public partial class SampleClass : MonoBehaviour { public void Func(){ Debug.Log(this.aaa); } }
実行結果
10 |
こんな感じで別ソースファイルで定義されているメンバー関数も
partialを使うことで同一クラスのメンバーとして認識されるんですね〜〜
partialなクラスを定義するための条件としては
- partialというキーワードをつける(当たり前だが)
- クラス名は統一させる(GameObjectにAddさせるときはソースファイル名も統一させる)
ちなみに同一クラスとして認識されるので、非公開メンバも参照可能っぽい
partialを用いたクラス設計
実際に現場では、partialを用いたクラス設計をした
今回紹介する例としては
partial + Stateパターン
Stateパターンはデザインパターンの1つだが、
partialを利用することで、綺麗に実装することができた!
サンプルソース
Player.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public partial class Player : MonoBehaviour { public interface IPlayerState { /// <summary> /// この状態になったときに実行される /// </summary> void OnEnter(); /// <summary> /// この状態の間、毎フレーム実行される /// </summary> void OnUpdate(); /// <summary> /// この状態ではなくなるときに実行される /// </summary> void OnExit(); /// <summary> /// 現在の状態を取得する /// </summary> /// <returns>現在の状態</returns> IPlayerState GetCurrentState(); } private float hp; private float power; private float speed; // Use this for initialization void Start () { //処理 } // Update is called once per frame void Update () { //処理 } }
PlayerAttackState.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public partial class Player : MonoBehaviour { private class AttackState : IPlayerState { Player _; public AttackState(Player player){ _ = player; } void IPlayerState.OnEnter() { //処理 } void IPlayerState.OnUpdate() { this.Punch(_.power); } void IPlayerState.OnExit() { //処理 } IPlayerState IPlayerState.GetCurrentState() { return this; } void Punch(float power){ //処理 } } }
partialを利用することで、プレイヤーという1つのクラスを複数に分けることができ、
この場合だと、状態別にプレイヤーのクラスを分割することができクラスの整理がしやすい!
また、状態クラスを内部クラス化させているのは、
内部クラスからは外部クラスの非公開メンバーを参照することが可能なため、
状態クラスから、プレイヤーの非公開なステータスにアクセスできたり、、、と割と使い勝手がいい
さらに非公開メンバーなので、それ以外のクラスからは見えないようにカプセル化されていたり
Stateパターンを実装する時には、こんなやり方もありかも?