Unity公式が公開しているプログラミングパターンを読み取ってみた！～その5. DependencyInversionPrinciple(依存性逆転の原則)～

# はじめに
Unity公式がプログラミングパターンのデモを説明書と共に全12種公開していたので、1つずつ読み取っていきたいと思います！
英語の説明書でしたので間違った解釈をしているかもしれませんが、ご了承下さい！
最初の5種は、SOLID原則に沿ったデモとなっており、コードのみが公開されています。
残り7種は、Scene付きのデモが入っていますので、ZIPファイルをダウンロードして試してみてください。
今回は、5つ目のDependencyInversionPrinciple(依存性逆転の原則)についてです。

https://github.com/Unity-Technologies/game-programming-patterns-demo

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

# 環境
OS : Windows10
Unity バージョン : 2021.3.8f1

# DependencyInversionPrinciple(依存性逆転の原則)とは
依存性逆転の原則(DIP)は、高レベルモジュールは低レベルモジュールから直接何もインポートしてはならないという原則です。
どちらも抽象化に依存する必要があります。
例えばあるクラスが別のクラスを関係を持つ場合、依存関係、または、結合があります。
1つのクラスが別のクラスの挙動について、あまりにも依存している場合、最初のクラスを変更すると別クラスが損傷する可能性があります。
結合度が高いことで一部のエラーが多くのエラーに発展する可能性があります。
理想はクラス間の依存関係をなるべく少なくすることです。

# デモ
キャラクターが探索し、スイッチを押すとドアが開閉するというゲームを作成しているとします。
DoorクラスとSwitchクラスを作成するとすると、以下はSwitchクラスがDoorクラスに依存している状態になります。

### 悪いコード
```C#
public class Switch : MonoBehaviour
{
    public Door door;
    // スイッチのON/OFF
    public bool isActivated;
    // スイッチが押されたときの処理
    public void Toggle()
    {
        if (isActivated)
        {
            // スイッチがON→OFFになる
            isActivated = false;
            door.Close();
        }
        else
        {
            // スイッチがOFF→ONになる
            isActivated = true;
            door.Open();
        }
    }
}

public class Door : MonoBehaviour
{
    public void Open()
    {
        Debug.Log("The door is open.");
    }
    public void Close()
    {
        Debug.Log("The door is closed.");
    }
}
```
スイッチを押したらトラップが発動するといったTrapクラスを実装するとなるとどうでしょうか？
メソッドを新たに追加することはできますが、[オープン・クローズドの原則](https://qiita.com/kazumatakata/items/f60a2d00a11066fad678)に違反することになります。
ここでも抽象化が役に立ちます。クラス間にISwichableというインターフェースを挟むことで以下のようになります。

### 良いコード
```C#
public interface ISwitchable
{
    // スイッチのON/OFFを取得のみ
    public bool IsActive { get; }
    public void Activate();
    public void Deactivate();
}
```
```C#
public class Switch : MonoBehaviour
{
    public ISwitchable client;
    public void Toggle()
    {
        if (client.IsActive)
        {
            client.Deactivate();
        }
        else
        {
            client.Activate();
        }
    }
}
```
```C#
public class Door : MonoBehaviour, ISwitchable
{
    // スイッチのON/OFF
    private bool isActive;
    public bool IsActive => isActive;
    public void Activate()
    {
        isActive = true;
        Debug.Log("The door is open.");
    }
    public void Deactivate()
    {
        isActive = false;
        Debug.Log("The door is closed.");
    }
}
```
これでSwitchクラスはISwitchableに依存し、DoorクラスはISwitchableを実行するようになりました。(依存性逆転)
これでスイッチを押すことでトラップも発動するとしたら、TrapクラスにISwitchableを実装すれば良いことになります。
```C#
public class Trap : MonoBehaviour, ISwitchable
{
    // スイッチのON/OFF
    private bool isActive;
    public bool IsActive => isActive;

    public void Activate()
    {
        isActive = true;
        Debug.Log("The trap is active.");
    }

    public void Deactivate()
    {
        isActive = false;
        Debug.Log("The trap is inactive.");
    }
}
```
このように疎結合にするだけで、後からスイッチを押したときの機能はISwitchableを実装するだけで良くなりました。

# 参考

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