個人的な見解
新作ゲームのジャンル紹介で「デッキ構築型ローグライトストラテジー」とか「ハクスラ型ダンジョン探索マルチRPG」とか目にするとそれだけでお腹一杯になる皆さんこんにちは。「ドラマチック謎解きアドベンチャー」という言葉も目にしましたが「ドラマチック」かどうかはこちらが判断するので勝手に名乗らないで下さい。
デザインパターン
前回の記事で紹介しましたがUnity公式からゲーム開発で使用するデザインパターンを学習するためのサンプルプロジェクトが公開されています。
デザインパターンは先人の経験に基づいたデザイン (設計) のパターンです。デザインパターンの要不要の議論はさておき、ゲームを設計する際の思考材料として覚えておいても損はありません。
公式サンプルではプロジェクト内のディレクトリ別に各デザインパターンに対してそれを使用したサンプルプロジェクトが内包していますが、今回はその中から「6 Factory」を紹介したいと思います。
Factoryパターン
Factoryパターンとは特定の機能を持つクラスに対して「インスタンスの生成」と「具体的な処理の実装」を分離して行うパターンのことを指します。
Factory=工場、だからといってこっちの工場じゃない
「車」を例にとると、「車」には「前輪駆動車」「後輪駆動車」「四輪駆動車」と駆動方式に違いがありそれに伴って内部の機構も異なっていますが、「車」を使用する側(ユーザ)にとってみれば内部機構の違いは認識せずに、「アクセル」を押せば「前進」し、「ハンドル」を回せば「左右に旋回」して欲しいと思います。
この為、「車」には「アクセル」と「ハンドル」というインターフェイスが「前輪駆動車」「後輪駆動車」「四輪駆動車」すべてに共通して存在しており、各駆動車はインターフェイスに応じた「前進」「旋回」の機能を実装します。
この時「車」というインスタンスを上位(ユーザ)に提供する際に
- 各駆動車で共通のインターフェイスをもった「車」を作成するクラス:Creater
- 各駆動車で「前進」「旋回」の機能を実装するクラス:Product
で分離しよう、という設計パターンがFactoryパターンとなります。
サンプルシーン
Factoryのサンプルシーンを実行してみるとこんな動作をします。
画面をクリックするとクリック位置に「パーティクルを放出する赤いボール」か「音を鳴らす黄色いボール」どちらかがランダムで生成されます。(上の動画はGIFのため音がありません)
このシーンのHierarchyを見ると「ClickToCreate」というオブジェトの配下に「FactoryA」「FactoryB」というオブジェトが配置されているのが分かります。
画面のクリックは「ClickToCreate」にアタッチされた「ClickToCreate」クラスで検知し、ランダムで「FactoryA」/「FactoryB」どちらかに対してボールを生成する依頼を行っています。
「FactoryA」では「赤いボール」が生成され、「FactoryB」から「黄色いボール」が生成されています。
FactoryA/FactoryBにはそれぞれCreaterとなる「ConcreteFactoryA」「ConcreteFactoryB」クラスがアタッチされており、どちらも抽象クラス「Factory」を継承しています。
「Factory」ではインスタンス生成を依頼するための「GetProduct」メソッドが用意されています。
一方、「パーティクルを放出する」「音を鳴らす」という機能はインターフェイス「IProduct」を継承した「ProductA」「ProductB」クラスの「Initialize」メソッドで実装され、「赤いボール」オブジェトに「ProductA」が、「黄色いボール」オブジェトに「ProductB」がアタッチされています。
この状態で「ClickToCreate」クラスから各Factoryに「GetProduct」を通じてインスタンス生成が依頼された場合
- 「FactoryA」では「ProductA」がアタッチされた「赤いボール」を生成し、「Initialize」を実行
- 「FactoryB」では「ProductB」がアタッチされた「黄色いボール」を生成し、「Initialize」を実行
を行うことでクリック位置に「パーティクルを放出する赤いボール」or「音を鳴らす黄色いボール」を生成させています。
各クラスの関わりを図で描くとこんな感じ、「インスタンス生成」の役割を「Factory」クラスが行い、「処理の実装」を「Product」クラスで行っている事が分ると思います。
今回のまとめ
Factoryパターンとは「インスタンスの生成」と「具体的な処理の実装」を分離して行うパターンです。
このパターンを利用すると、新しいオブジェクトが増えた場合でも新しいFactoryを作るだけとなり、利用する側は大きく処理を変更する必要がありません。
また、機能の追加/削除を行う場合もインターフェイスの変更とFactory内部を修正するだけなので影響範囲が最小限で収まります。
デメリットとしては作成するクラスが多くなる分コード量が多くなるという事と、上のような図を描かないと全体を把握しづらい、という事でしょうか。
ここら辺は使い所によって考慮する必要があると思います。