【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 1:単一責任の原則)

# ●はじめに
前:　[【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 0)](https://qiita.com/kiku09020/items/09308a4e6270f686d709)

今回は、SOLID原則のSの部分である、単一責任の原則(SingleResponsibility)について、Unityの公式プロジェクトを参照しながら学んでいきます！(プロジェクトのリポジトリへのリンクは、前回の記事に記載しています。)


# ●単一責任の原則とは？
- めちゃくちゃ簡単に言うと、**1つのクラスに詰め込み過ぎるなっていう原則**です。(間違ってたら指摘ください)
- 詰め込みすぎずに細分化すれば、**多人数での開発などで担当を分担**したり、**バグの数を減らす**ことができます。

# ●プロジェクトの内容
では、実際にUnity公式のプロジェクトから単一責任の原則のデザインパターンの例を見てみましょう。

- Projectビューの、[**1 SingleResponsibility**]のScripts内に、今回のデザインパターンにならったスクリプトがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2419795/1b0c41a5-3e86-bf07-f975-4f3ce8001524.png)

- 内容はこんな感じです。
    1. Player
    1. PlayerAudio
    1. PlayerInput
    1. PlayerMovement
    1. UnrefactoredPlayer

### ○Player
- 以下3つのスクリプトの管理とかをするクラスっぽい。
- デフォルトだと、特に何もしないクラス。

### ○PlayerAudio
- プレイヤーに関する音声を再生するクラス。

### ○PlayerInput
- プレイヤーに関する入力判定をするクラス。

### ○PlayerMovement
- プレイヤーの移動に関するクラス。

### ○UnrefactoredPlayer
- 訳してみると、「整理されていないプレイヤー」　みたいな感じです。
- このスクリプトは、やってはいけないクラスの見本です。





# ●コードを見てみる
## ○UnrefactoredPlayer
まずは、ダメな例である「UnrefactoredPlayer」を見てみます。

<details><summary><b>クリックして展開</b></summary>

```UnrefactoredPlayer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DesignPatterns.SRP
{
    // Even though this class is short, it violates single-responsibility.
    // Too many things will cause the class to update, and extending the class will be more difficult.

    public class UnrefactoredPlayer : MonoBehaviour
    {

        [SerializeField] private string _inputAxisName;

        [SerializeField] private float _positionMultiplier;

        private float _yPosition;

        private AudioSource _bounceSfx;

        private void Start()
        {
            _bounceSfx = GetComponent<AudioSource>();
        }

        private void Update()
        {
            float delta = Input.GetAxis(_inputAxisName) * Time.deltaTime;

            _yPosition = Mathf.Clamp(_yPosition + delta, -1, 1);

            transform.position = new Vector3(transform.position.x, _yPosition * _positionMultiplier, transform.position.z);
        }

        private void OnTriggerEnter(Collider other)
        {
            _bounceSfx.Play();
        }
    }

}

```
</details>

上部のコメントの翻訳を見てみましょう

>このクラスは短いですが、単一責任に違反しています。
**あまりにも多くのことがクラスの更新を引き起こし、クラスの拡張がより困難になります**。

**入力、移動、当たり判定などを1つのクラスにまとめちゃってる**感じですね。
Unity始めたての頃はこんな感じでもいいと思いますが、本格的なゲームを作ろうとしたときにこんな感じだと、コメントの通り拡張性が失われちゃいます…。

**入力は入力クラス、移動は移動クラス…などと細分化することが、単一責任の原則に則ったコードになります。**


## ○Player

<details><summary><b>クリックして展開</b></summary>

``` Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace DesignPatterns.SRP
{
    [RequireComponent(typeof(PlayerAudio), typeof(PlayerInput), typeof(PlayerMovement))]
    public class Player : MonoBehaviour
    {
        [SerializeField] private PlayerAudio playerAudio;
        [SerializeField] private PlayerInput playerInput;
        [SerializeField] private PlayerMovement playerMovement;

        private void Start()
        {
            playerAudio = GetComponent<PlayerAudio>();
            playerInput = GetComponent<PlayerInput>();
            playerMovement = GetComponent<PlayerMovement>();
        }
    }


}

```
</details>

- [**RequireComponent**]で、このスクリプトをAddComponentしたときに、**自動的に指定されたスクリプトもコンポーネントに追加する**らしい。付け忘れ防止とかになるので、そこそこ便利かも。
- デフォルトの状態だと、ただコンポーネント取得するだけで、特に何もしてないです。


## 〇それ以外のクラス
- 中身は特に詳しく説明はしないです。細分化することが大切ってことが分かればいいので…。



# ●さいごに
よくあるのが、**Managerっていう名前のクラスを作って、そこになんでも詰め込んじゃう**っていうやつですが、単一責任の原則とは反しています(僕も現在進行形でそれしてます…。)
これも危険っぽいので、見直して設計してみます。

前の記事でも紹介しましたが、公式のちゃんとしたPDFの説明書があるので(※英語)、よろしければどうぞ↓

https://resources.unity.com/games/level-up-your-code-with-game-programming-patterns

次:[【Unity】公式プロジェクトから、デザインパターンを学んでみよう(Part 2:開放・閉鎖の原則)](https://qiita.com/kiku09020/items/bfcf01511dc385c797ac)