Prototype

  • 原型となるインスタンスをコピーして新しいインスタンスを生成するパターン

    • 親クラスでインスタンスをコピーするためのメソッドを定義し、子クラスで自分自身のコピーを返すように実装する
  • コピーには「浅いコピー」と「深いコピー」がある

    • 浅いコピー
      • 変数に格納された値がそのままコピーされる
      • オブジェクトの参照を格納した変数では、参照がコピーされる →どちらかのオブジェクトを変更すると、もう片方も変更される
    • 深いコピー
      • オブジェクトの参照を格納した変数では、実体がコピーされる →どちらかのオブジェクトを変更しても、もう片方に影響を与えない
  • 「継承」と「ポリモーフィズム」を利用したパターン

    • PrototypeConcretePrototypeクラスの間に継承(実装)関係
    • Clientクラスでは親クラスであるPrototypeクラスで提供されているAPIのみを使ってプログラミングを行う
    • ClientクラスとConcretePrototypeに依存関係がないので、ConcretePrototypeの差し替えは追加・修正が可能(インターフェース分離の原則)

メリット・デメリット

メリット
  • オブジェクトの生成処理を隠蔽できる
  • 構築済みのプロトタイプのクローンの作成を使うことにより、初期化コードの重複を削減
  • 利用者と具体的なクラスの結合度を弱められる
デメリット
  • ディープコピーとシャローコピーの違いを理解していないと想定外のバグを発生させる恐れがある

用途

  • クラスからのインスタンス生成が難しい場合
    • ユーザー操作によって生成されたグラフィックオブジェクトなど
    • 例)パワーポイントの図形のコピー
  • インスタンス化のコストがコピーよりも高い場合

デザインパターンの種類

生成に関するデザインパターン

例(Mermaid)

  • Manager
    • コピーするオブジェクトを管理しつつ、インスタンスを要求された際にコピーを返す
  • Prototype
    • インターフェースもしくは抽象クラス
    • インスタンスをコピーして新しいインスタンスを作るためのメソッドを定める
  • ConcretePrototype
    • Prototypeを実装(継承)する子クラス
    • Prototypeで定義されたコピー用のメソッドを実装する
classDiagram
	class Manager{
	}
	class Prototype{
		<<interface>>
		createCopy()
	}
	class ConcretePrototype{
		createCopy()
	}
	Prototype <-- Manager
	Prototype <|.. ConcretePrototype
	
商品のコピーを行う場合
classDiagram
	class ItemManager {
		-items Record<string,ItemPrototype>
		registerItem(key string,item ItemPrototype)
		create(key string)
	}
	class ItemPrototype {
		<<abstract>>
		name string
		detail Object
		addComment()
		createCopy() ItemPrototype
	}
	class DeepCopyItem {
		createCopy():ItemPrototype
	}
	class ShallowCopyItem {
		createCopy():ItemPrototype
	}
	ItemPrototype <-- ItemManager
	ItemPrototype <|-- DeepCopyItem
	ItemPrototype <|-- ShallowCopyItem