gof-prototype について
gof-prototypeは、既存インスタンスを基に派生オブジェクトを作る開発者向けに、Prototypeパターンを解説するスキルです。Kotlinのdata class.copy()、プロトタイプレジストリ、浅いコピーのリスクを扱います。
主な機能
- 01単純なプロトタイプとレジストリの解説
- 02Kotlinのdata class.copy()の説明
- 03パターンの適用判断の指針
- 04浅いコピーと共有状態のリスク
- 05アンチパターンと関連パターンの紹介
活用シーン
- 01テンプレートから少し異なるオブジェクトを作成
- 02名前付きプロトタイプを管理してカスタマイズ
- 03オブジェクト生成にコピーが適するか判断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-prototypeインストール後、Claude Code で/gof-prototypeを入力して読み込まれたか確認します。
詳細
1 行での要約
コンストラクターを呼び出すのではなく、既存のインスタンス(プロトタイプ)をコピーして新しいオブジェクトを作成します。構築にコストがかかる場合、いくつかのフィールドだけを変更したい場合、または定型の形状を登録したレジストリがある場合に便利です。
このスキルを使う場合
- オブジェクトの構築にコストがかかる、または繰り返したくない副作用があります。
- 「テンプレート」インスタンスがあり、いくつかのフィールドを変更したバリエーションが必要です。
- 定型インスタンスのレジストリが必要で、利用側がそれらを複製してカスタマイズできます。
- Kotlin での代表的な実装は、
data class.copy(field = newValue)です。これはまさにこのパターンです。
このスキルを使わない場合
- 構築が低コストでステートレスです。そのままコンストラクターを呼び出してください。
- 複雑なオブジェクトグラフのディープクローンが必要です。Prototype の契約は通常、浅いコピーです。ディープクローンはそれ自体が別の課題です。
- まだ実際には存在しないものを「コピー」して、難しい構築の問題を回避しようとしています。それは問題の兆候です。
主な内容
2 つの種類があります。
シンプルな Prototype。 オブジェクトに、同じフィールド値を持つ新しいインスタンスを返す clone()(または copy())メソッドがあります。呼び出し側はベースとなるインスタンスを取得してコピーし、そのコピーを変更します。Kotlin では、すべての data class に copy() が標準で用意されており、名前付き引数で上書きすることもできます。
val baseRequest = HttpRequest(method = GET, url = "/users", headers = standardHeaders)
val authedRequest = baseRequest.copy(headers = standardHeaders + auth)
Prototype レジストリ。 中央のレジストリに、名前付きのプロトタイプインスタンスを保持します。利用側はレジストリに名前("weekday-shift"、"weekend-shift")を指定してプロトタイプを要求し、カスタマイズ可能なクローンを取得します。プロトタイプがコードではなく設定データである場合に便利です。
このパターンの価値は、意図を明確にできることです。「この既存のインスタンスに似た新しいインスタンスを、次の点だけ変更して作る」という説明は、すべてのフィールドを再構築するよりもわかりやすくなります。
判断の指針
- Kotlin では、
data class.copy()がデフォルトの Prototype です。明示的なレジストリを使うのは、プロトタイプに名前が付いている場合、設定されている場合、または数が多い場合に限ります。 data classではない型の場合、copy()がディープコピーか浅いコピーかを意識して決め、ドキュメントに記載してください。- ネストされた可変状態に注意してください。
data classのcopy()がコピーするのは参照であり、参照先のオブジェクトではありません。共有されたネスト済みリストを変更すると、元のインスタンスとコピーの両方に影響します。
アンチパターン
- コピーとほぼ同じだが、厳密には異なるインスタンスを意図せず作る
clone()メソッド。正確にコピーするか、メソッド名を変更してください。 - コピーせずに複数の利用側で共有する可変プロトタイプ。レジストリ内のインスタンスは時間とともに変化してしまいます。
- コンストラクターがないことを補うための Prototype の実装。コンストラクターを修正してください。
関連項目
gof-factory— 特に各「バリエーション」が実際には異なる具体型である場合、Prototype の代わりとして適切なことがあります。gof-builder— バリエーションがフィールド単位の上書きではなく、構造(異なる手順)に関する場合に使います。gof-kotlin-idioms—data class.copy()は言語機能としての Prototype です。
参考資料
- Design Patterns(GoF、1994)、第 3 章 — Prototype。(HFDP 第 2 版には含まれていません。)
- Kotlin Design Patterns and Best Practices(Alexey Soshin)、第 2 章 — Kotlin の
copy()を軸に解説する Prototype。