【Unity】Unityで学ぶデザインパターン02: Builder パターン【デザパタ】

# はじめに
様々な言語で「デザインパターン」の本が世の中にありますが、筆者個人の経験では
`いまいちピンとこない例` `いまいちピンとこないコード` で説明されてることが多く、
`結局これっていつ使うの？` という疑問に答えるには仕事仲間等との議論をしないと
辿り着けないことが多々ありました。

そこで特に「ゲーム開発ではどう使うか？」にフォーカスを当てて、実践的な例を交えて
デザインパターンの説明の需要があると思い記事を作りました。

## デザインパターンを学ぶ理由

デザインパターンを学ぶ理由としては
1. 車輪の再発明の防止
1. 長文で読みにくいコード（可読性の低いコード）を減らす
1. コードを疎結合にして変更に強くなる(変更時のコスト・変更箇所を減らす)
1. モジュールとして使いまわせるように、コードの再利用性を高める
といった効果を期待できます。

## 対象読者
Unity 全くの初心者(インストールしただけで触ったことがないような方)はお断りです。
最低限以下のことは理解・経験を積んでおくことが必須になります。

- MonoBehaviour 継承クラスでコードを書いたことがある
- C# のピュアクラスを用いた自作クラスを作ったことがある
- クラスの継承という概念は知っている

そのため、`脱・初心者` `中級者へのステップアップ` として `デザインパターンを学ぶ` のが良いと思います。


# デザパタ記事リンク
## 生成系
1. [AbstractFactory パターン](https://qiita.com/Cova8bitdot/items/e863cecf48c0529ba05a)
1. [Builder パターン](https://qiita.com/Cova8bitdot/items/9dcdfeb0641bc774b1f8)(本記事)
1. [FactoryMethod パターン](https://qiita.com/Cova8bitdot/items/61a38fd51735f321e564)
1. [Prototype パターン](https://qiita.com/Cova8bitdot/items/0bc251bc36201985c204)
1. [Singleton パターン](https://qiita.com/Cova8bitdot/items/29b7064c7472a6f34972)

## 構造系
1. [Adapter パターン](https://qiita.com/Cova8bitdot/items/f09776957073cf64902b)
1. [Bridge パターン](https://qiita.com/Cova8bitdot/private/5b528216952c74436045)
1. [Composite パターン](https://qiita.com/Cova8bitdot/items/1c57d856027a33e99eb0)
1. [Decorator パターン](https://qiita.com/Cova8bitdot/items/e1373a756b3dfd86c920)
1. [Facade パターン](https://qiita.com/Cova8bitdot/items/bdf0976bdfa83e57f121)
1. [Flyweight パターン](https://qiita.com/Cova8bitdot/items/7f1f1f04b46ebaf43c5e)
1. [Proxy パターン](https://qiita.com/Cova8bitdot/items/8a27137812e103ec1ee3)

## 様態・ふるまい系
1. [Chain of Responsibility パターン](https://qiita.com/Cova8bitdot/items/66c62dd96adffda7e72e)
1. [Command パターン](https://qiita.com/Cova8bitdot/items/9a88f7fc0782c729f97c)
1. [Interpreter パターン](https://qiita.com/Cova8bitdot/items/a871c1de813d14049934)
1. [Iterator パターン](https://qiita.com/Cova8bitdot/items/302f19863cc3b2235625)
1. [Mediator パターン](https://qiita.com/Cova8bitdot/items/be33b97f35c84e814df7)
1. [Memento パターン](https://qiita.com/Cova8bitdot/items/ae7e6f5d2da7b07d379b)
1. [Observer パターン](https://qiita.com/Cova8bitdot/items/632782ad5264baf6a366)
1. [State パターン](https://qiita.com/Cova8bitdot/items/ab9fc16ac3a6657fdce0)
1. [Strategy パターン](https://qiita.com/Cova8bitdot/items/28dd773075cf6e9fefee)
1. [TemplateMethod パターン](https://qiita.com/Cova8bitdot/items/f0bed164ef6563b489d0)
1. [Visitor パターン](https://qiita.com/Cova8bitdot/items/15c56d40435adf63891d)


# Builder　パターンについて
Builder パターンとは `複雑なものから成るObjectを構成する` デザインパターンです。
特に `構成素材` と `構成過程` が重要、柔軟にしたい場合に利用されます。

・・・

[AbstractFactory](https://qiita.com/Cova8bitdot/items/e863cecf48c0529ba05a) と何が違うのか？とお考えの読者の方、　 `非常に鋭い`　です。

## Abstract Factoryとの違い
簡単に答えるなら [AbstractFactory](https://qiita.com/Cova8bitdot/items/e863cecf48c0529ba05a) は `0 -> 1 を行うもの` 、Builder は `複数のものをまとめあげるもの` といった形です。
特に、Factory に関しては生成プロセスに対して外側からは介入することができません。一方Builder は生成過程に介入しやすいため、単純な[AbstractFactory](https://qiita.com/Cova8bitdot/items/e863cecf48c0529ba05a)に比べたら柔軟性が上がっています。

## ゲームでの利用例
今までは敵の生成では `EnemyFactory` を用意して生成することで問題ありませんでした。
しかし敵でもバリエーションを出したい状況はかなりの高確率で発生します。

たとえば「スケルトン(骸骨)」の敵を考えてみましょう。
UnityのAssetStore を検索すると以下のようなアセットが公開されています。

https://assetstore.unity.com/packages/3d/characters/enemy-skeleton-warrior-239957

上記アセットからも分かる通り「スケルトン」一つとっても武器だけでも「なし」「刀」「弓」、防具も「あり」「なし」の組み合わせがあるため
全部で6通りのスケルトンを作ることができます。

このように考えると `SkeletonFactory` を作ろうとしても工場の種類の組合せ爆発が起こります。
- NormalSkeletonFacroy
- WarriorSkeletonFacroy
- ArcherSkeletonFactory
- ArmoredSkeletonFacroy 
- ArmoredWarriorSkeletonFacroy
- ArmoredArcherSkeletonFactory

名前も長いし、同じようなFactory を作らなきゃいけないですし、無駄にコードも増えて保守性も下がります。

そこで以下のように考えてみましょう。

1. 「スケルトン」「各種武器」「防具」はそれぞれの工場から作成します、
1. `SkeletonBuilder` は工場から渡された素材を組み合わせて敵としてのスケルトンを出荷するのみに特化させます。
1. このときBuilder には 武器・防具は渡されない場合もあります

![スクリーンショット 2023-03-28 18.45.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65257/f9c3ba82-c6ce-c230-4f33-6a5b46208355.png)

このときSkelteonBuilder は以下のようなAPIを持っています。
```SkeletonBuilder.cs

public abstract class BaseSkeletonBuilder
{
	public abstract void SetSkeleton(Skeleton body);
	public abstract void SetWeapon(BaseWeapon weapon);
	public abstract void SetArmor(BaseArmor armor);

	public abstract Skeleton Build()
}

```
大元となるSkeleton は必須ではありますが、そのほかはオプションで `あってもなくても良い` というのが面白いところです。
Nullならセットしないだけで、必要に応じて適切にオプションのオブジェクトを登録するだけで、あとはBuilderでBuild()するだけで敵が作られるというカラクリです。
また、今は刀と弓ですが、「魔法使い」や「神官」などスケルトンのジョブが増えた時も「渡す武器・防具」を変えるだけで対応可能ですね。

# まとめ
Builder はFactory などから提供される素材を組み合わせて新しくオブジェクトを作るときに便利なデザインパターンです。
Factory よりも `素材` や `生成過程` を柔軟にしたいときに大きく効果を発揮します。


# 参考

ピクトグラム：　https://icooon-mono.com/license/