【デザインパターン】Prototypeを学ぶ【C#】

C#

一言で言うと…

  • 既存のインスタンスを複製(クローン)して新しいオブジェクトを生成する仕組み

概要

Prototype パターンは、GoF デザインパターンの一つで、生成に関するデザインパターンです。

オブジェクトの生成コストが高い場合や、同じ設定を持つオブジェクトを大量に作りたい場合に、 既存のインスタンスをテンプレートとして複製(Clone)することで効率的にオブジェクトを生成します。

ゲーム開発においては、同じ設定の敵キャラクターやアイテムを大量にスポーンする場面でよく活用されます。 毎回ゼロからオブジェクトを構築するより、プロトタイプをコピーするほうが処理コストを抑えられます。

構成

classDiagram
    class IPrototype {
        << interface >>
        + Clone() IPrototype
    }
    class ConcretePrototype {
        + field1
        + field2
        + Clone() IPrototype
    }
    ConcretePrototype ..|> IPrototype : implements
    Client ..> IPrototype : << use >>
要素役割
IPrototypeClone() メソッドを定義するインターフェース
ConcretePrototype実際にクローン処理を実装するクラス
Clientプロトタイプを複製して使う利用者

実装例(C#)

クラス概要

早速実装例です。今回はC#でゲーム開発を行う場合を想定してみました。

利用ケースは以下のように、敵キャラクターのプロトタイプを複製してスポーンさせる機構です。

  • IEnemy:プロトタイプインターフェース(IPrototype)
  • SlimeDragon:複製可能な敵クラス(Concrete Prototype)
  • クライアント:プロトタイプを複製して敵をスポーン

ソースコード

1. プロトタイプインターフェース(IPrototype)

C#
/// <summary>
/// 敵のプロトタイプインターフェース (IPrototype)
/// </summary>
public interface IEnemy
{
    string Name { get; }
    int Hp { get; }
    int Attack { get; }

    /// <summary>自分自身を複製して返す</summary>
    IEnemy Clone();

    void ShowInfo();
}

2. 具象プロトタイプ(Concrete Prototype)

C#
using System;

/// <summary>
/// スライム (Concrete Prototype)
/// </summary>
public class Slime : IEnemy
{
    public string Name { get; private set; }
    public int Hp { get; private set; }
    public int Attack { get; private set; }

    public Slime(string name, int hp, int attack)
    {
        Name   = name;
        Hp     = hp;
        Attack = attack;
    }

    /// <summary>MemberwiseClone で浅いコピーを返す</summary>
    public IEnemy Clone() => (IEnemy)this.MemberwiseClone();

    public void ShowInfo() =>
        Console.WriteLine($"[{Name}] HP:{Hp} ATK:{Attack}");
}

/// <summary>
/// ドラゴン (Concrete Prototype)
/// </summary>
public class Dragon : IEnemy
{
    public string Name { get; private set; }
    public int Hp { get; private set; }
    public int Attack { get; private set; }
    public string Element { get; private set; }

    public Dragon(string name, int hp, int attack, string element)
    {
        Name    = name;
        Hp      = hp;
        Attack  = attack;
        Element = element;
    }

    public IEnemy Clone() => (IEnemy)this.MemberwiseClone();

    public void ShowInfo() =>
        Console.WriteLine($"[{Name}({Element})] HP:{Hp} ATK:{Attack}");
}

C# の MemberwiseClone() を使うとフィールドを浅いコピーで複製できます。

深いコピー(deepcopy: 参照型フィールドも含めて独立させる)が必要な場合は、コピーコンストラクタや手動コピーを実装します。

3. クライアントコード

C#
class PrototypeSample
{
    static void Main()
    {
        // プロトタイプとなるインスタンスを1つ作成
        IEnemy slimeProto  = new Slime("スライム", 30, 5);
        IEnemy dragonProto = new Dragon("ドラゴン", 500, 80, "炎");

        // プロトタイプを複製してスポーン
        IEnemy slime1 = slimeProto.Clone();
        IEnemy slime2 = slimeProto.Clone();
        IEnemy boss   = dragonProto.Clone();

        slime1.ShowInfo();  // => [スライム] HP:30 ATK:5
        slime2.ShowInfo();  // => [スライム] HP:30 ATK:5
        boss.ShowInfo();    // => [ドラゴン(炎)] HP:500 ATK:80

        // 複製元と複製先は別インスタンス
        Console.WriteLine(ReferenceEquals(slimeProto, slime1)); // => False
    }
}

使いどころ

  • 同じ設定を持つオブジェクトを大量に生成したいとき(敵の大量スポーン
  • オブジェクトの生成コストが高く、毎回ゼロから作るのが非効率なとき
  • 生成するクラスに直接依存させたくないとき(インターフェース経由でClone)

長所・短所

✅ 長所

  • 既存インスタンスを複製するため、初期化コストを削減できる
  • 具体的なクラスに依存せずにオブジェクトを生成できる
  • 複雑な初期化処理を持つオブジェクトを簡単に複製できる

⚠️ 短所

  • 深いコピーが必要な場合、実装が複雑になる
  • 循環参照を持つオブジェクトのクローンは特別な対応が必要
  • MemberwiseClone() の浅いコピーで十分かどうかを常に意識する必要がある

他GoFパターンとの比較・関係

Factory Method / Abstract Factory との違い

Factory Method や Abstract Factory は「クラスからオブジェクトを new して生成する」仕組みです。 Prototype は「既存のインスタンスをコピーして生成する」点が根本的に異なります。

生成元がクラスか、インスタンスかという違いです。

パターン生成の起点
Factory Methodクラス定義(new)
Abstract Factoryクラス定義(new)の組み合わせ
Prototype既存インスタンス(Clone)

Builder との関係

Builder は「手順を踏んで段階的に組み立てる」パターンです。

Prototype は「完成済みのオブジェクトをコピーする」パターンです。

初期設定が複雑なオブジェクトを Builder で一度組み立て、それを Prototype で複製するという組み合わせもよく使われます。

Singleton との関係

Prototype で複製元となるプロトタイプオブジェクトを Singleton で管理するパターンも一般的です。 「どこからでも同一のプロトタイプにアクセスし、そこから複製する」という設計です。

まとめ

  • Prototype パターンは、既存インスタンスを複製(Clone)して新しいオブジェクトを生成する
  • C# では MemberwiseClone() で浅いコピーを、参照型フィールドがある場合は深いコピーを実装する
  • ゲーム開発では敵キャラやアイテムの大量スポーンに有効
  • Factory Method との違いは「クラスから new」か「インスタンスからコピー」かにある
  • Builder で組み立てたオブジェクトを Prototype で複製するパターンもよく使われる

タイトルとURLをコピーしました