🧩 Prototype パターン
✅ 設計意図
- インスタンスの雛形(プロトタイプ)を複製して使うことで、初期化済みの処理・構造を再利用
- ベースとなるオブジェクトを
clone()
でコピーし、差分だけを上書きして扱う
✅ 適用理由
- 「ちょっと違うだけ」な処理や構造を、テンプレートベースで複製した方が保守性・再利用性が高い
- 大量の似た処理を
new
から毎回書いている場合に、共通化しやすい
✅ 向いているシーン
- 初期状態が共通で、差分だけ変更したいケース
- フォーム、設定オブジェクト、通知テンプレート、UI 構成などの複製
✅ コード例
- TypeScript
- PHP
- Python
interface ExporterPrototype {
clone(): ExporterPrototype;
export(data: string): void;
}
class PdfExporter implements ExporterPrototype {
constructor(private withLog: boolean = false) {}
clone(): ExporterPrototype {
return new PdfExporter(this.withLog);
}
export(data: string): void {
if (this.withLog) console.log("開始ログ");
console.log(`PDF出力: ${data}`);
if (this.withLog) console.log("完了ログ");
}
enableLogging(): void {
this.withLog = true;
}
}
// 利用例
const baseExporter = new PdfExporter();
baseExporter.enableLogging();
const cloned = baseExporter.clone();
cloned.export("請求書");
<?php
interface ExporterPrototype {
public function clone(): ExporterPrototype;
public function export(string $data): void;
}
class PdfExporter implements ExporterPrototype {
public function __construct(private bool $withLog = false) {}
public function clone(): ExporterPrototype {
return new PdfExporter($this->withLog);
}
public function export(string $data): void {
if ($this->withLog) echo "開始ログ\n";
echo "PDF出力: {$data}\n";
if ($this->withLog) echo "完了ログ\n";
}
public function enableLogging(): void {
$this->withLog = true;
}
}
// 利用例
$baseExporter = new PdfExporter();
$baseExporter->enableLogging();
$cloned = $baseExporter->clone();
$cloned->export("請求書");
import copy
from abc import ABC, abstractmethod
class ExporterPrototype(ABC):
@abstractmethod
def clone(self): pass
@abstractmethod
def export(self, data: str): pass
class PdfExporter(ExporterPrototype):
def __init__(self, with_log: bool = False):
self.with_log = with_log
def clone(self) -> "PdfExporter":
return copy.deepcopy(self)
def enable_logging(self):
self.with_log = True
def export(self, data: str):
if self.with_log:
print("開始ログ")
print(f"PDF出力: {data}")
if self.with_log:
print("完了ログ")
# 利用例
base_exporter = PdfExporter()
base_exporter.enable_logging()
cloned = base_exporter.clone()
cloned.export("請求書")
✅ 解説
このコードは Prototype
パターン を使用して、既存のオブジェクトを複製(クローン)し、
同じプロパティを持つ新しいインスタンスを生成する設計を実現している。
Prototype
パターンは、オブジェクトの生成をクラスに依存せず、既存のインスタンスをコピーして新しいインスタンスを作成するデザインパターン。
1. Prototype パターンの概要
- Prototype: クローン機能を提供するインターフェース
- このコードでは
ExporterPrototype
が該当
- このコードでは
- ConcretePrototype:
Prototype
を実装し、具体的なクローン処理を提供するクラス- このコードでは
PdfExporter
が該当
- このコードでは
- Client:
Prototype
を利用してオブジェクトを複製するコード- このコードでは
baseExporter.clone()
を呼び出してクローンを生成する部分が該当
- このコードでは
2. 主なクラスとその役割
ExporterPrototype
- Prototype の共通インターフェース
clone(): ExporterPrototype
メソッドを定義し、オブジェクトのクローンを生成export(data: string): void
メソッドを定義し、データを出力
PdfExporter
- ConcretePrototype クラス
clone
メソッドで自身のコピーを生成export
メソッドで PDF 出力を実行- ログ出力を有効化するための
enableLogging
メソッドを提供
3. UML クラス図
4. Prototype パターンの利点
- オブジェクト生成の柔軟性: クラスに依存せず、既存のインスタンスを基に新しいインスタンスを生成可能。
- 複雑な初期化処理の回避: クローンを使用することで、複雑な初期化処理を繰り返す必要がない。
- 拡張性: 新しいクラスを追加する場合も、
clone
メソッドを実装するだけで対応可能。
この設計は、既存のオブジェクトを基に新しいインスタンスを生成する必要がある場面で非常に有効であり、コードの柔軟性と再利用性を向上させる。