Unityにおける継承と合成(コンポジション)
目次
概要
Unityはコンポーネントベースの設計思想を採用しており、オブジェクトにさまざまな機能を付与するために「継承」ではなく「合成」を使用することが推奨されています。本資料では、継承と合成の違いをサンプルコードを用いて比較し、合成のメリットを解説します。
継承と合成(コンポジション)の違い
継承の特徴
- 親クラスと子クラスの関係で機能を共有します。
- 機能を拡張しやすい一方で、階層が深くなると保守性が低下します。
- クラス同士が強く結びつくため、再利用性が低くなる傾向があります。
合成(コンポジション)の特徴
- 小さな機能単位を「コンポーネント」として独立して実装し、必要に応じて組み合わせます。
- 再利用性が高く、機能の追加や変更が容易です。
- 各コンポーネントが独立しているため、他のスクリプトへの影響が少なくなります。
継承を使った例
以下の例は、プレイヤーキャラクターが「移動」と「ジャンプ」の機能を持つ場合です。
BaseCharacter.cs
using UnityEngine;
public class BaseCharacter : MonoBehaviour
{
public float speed = 5f;
// 移動処理
public virtual void Move()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime);
}
// Updateは子クラスでオーバーライド可能
public virtual void Update()
{
Move();
}
}
PlayerCharacter.cs
using UnityEngine;
public class PlayerCharacter : BaseCharacter
{
public float jumpForce = 5f;
// 移動処理を拡張し、ジャンプも追加
public override void Move()
{
base.Move(); // 親クラスの移動処理を呼び出す
if (Input.GetButtonDown("Jump"))
{
Jump();
}
}
private void Jump()
{
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
// Updateの挙動をカスタマイズ
public override void Update()
{
Move(); // オーバーライドされたMoveを呼び出す
}
}
問題点
PlayerCharacter
に特化したジャンプ処理がBaseCharacter
に影響しない設計が困難。- 他のオブジェクトに「移動」や「ジャンプ」機能を適用しにくい。
合成(コンポジション)を使った例
MoveComponent.cs
using UnityEngine;
public class MoveComponent : MonoBehaviour
{
public float speed = 5f;
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
transform.Translate(new Vector3(h, 0, v) * speed * Time.deltaTime);
}
}
JumpComponent.cs
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class JumpComponent : MonoBehaviour
{
public float jumpForce = 5f;
void Update()
{
if (Input.GetButtonDown("Jump"))
{
Jump();
}
}
private void Jump()
{
GetComponent<Rigidbody>().AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
使い方
- プレイヤーオブジェクトに
MoveComponent
とJumpComponent
をそれぞれアタッチします。 - 必要に応じて他のオブジェクトにも追加可能です(例: 敵キャラクターが移動だけを持つなど)。
合成(コンポジション)のメリット
再利用性
各機能が独立しているため、他のゲームオブジェクトにも簡単に使い回しが可能です。
柔軟性
必要な機能だけを組み合わせることで、オブジェクトごとに異なる動作を実現できます。
保守性
コンポーネントが独立しているため、変更が他のコードに影響を与えません。
単一責任の原則(SRP: Single Responsibility Principle)
各コンポーネントが1つの責任に集中しているため、コードがシンプルで読みやすくなります。
比較表
項目 | 継承 | 合成 |
---|---|---|
再利用性 | 低い | 高い |
拡張性 | 階層が深くなるほど難しい | コンポーネントを追加するだけで簡単 |
柔軟性 | 低い | 高い |
保守性 | 変更が他のクラスに影響する可能性あり | 独立しているため影響が少ない |
結論
Unityにおけるゲーム開発では、「継承」よりも「合成」を使用する方が柔軟で再利用性が高い設計を実現できます。特に大規模なプロジェクトや長期的な保守を考慮する場合、合成の設計思想を取り入れることを強く推奨します。
ディスカッション
コメント一覧
まだ、コメントがありません