Prototype パターン

Prototype パターン（英: Prototype pattern、プロトタイプ・パターン）とは、ソフトウェア開発で用いられる、生成に関するデザインパターンの1つである。生成されるオブジェクトの種別がプロトタイプ（典型）的なインスタンスであるときに使用され、このプロトタイプを複製して新しいオブジェクトを生成する。 このパターンは Abstract Factory パターンでなされるように、クライアント・アプリケーションにおいてオブジェクトの生成者をサブクラスにすることを回避する 標準的な方法（例えば'new'）で新しいオブジェクトを作ることによる固有のコストが所与のアプリケーションにとって高すぎる時にそれを回避する ために用いられる。 このパターンを実装するには、純粋仮想 (pure virtual method) の clone()メソッドを指定する抽象的（abstract）な基底クラスを宣言する。「多態性を持つコンストラクタ」の能力を必要とする全てのクラスは抽象的な基底クラスから自身を派生させ、clone()の操作を実装する。 クライアントは、ハードコードされたクラス名において"new"演算子を呼び出すコードを書く代わりに、プロトタイプにおいてclone()メソッドを呼び出すか、所望の特定の具体的（concrete）な派生クラスを指し示すパラメタを渡してファクトリメソッドを呼び出すか、clone()メソッドを他のデザインパターンにより供給される何らかの機構を通じて呼び出すかする。 Prototypeパターンではプロトタイプとなるインスタンスを用いて作成するオブジェクトの種別を指定する。本格的に生成を行う前に新しい生成物のプロトタイプが作られる場合も多いが、ここに挙げる例においてはプロトタイプは受動的なものであり自身の複製には関与しない。2つの同一の細胞が得られる有糸分裂は自己複製において能動的な役割を演じるプロトタイプの一例であり、よってPrototypeパターンの例示となる。細胞が分裂すると、同一の遺伝子型を持つ2つの細胞となる。言い換えれば、細胞はそれ自身を複製するのである。 /** * Prototype Class */ abstract class PrototypeFactory implements Cloneable { public Object clone() throws CloneNotSupportedException { // call Object.clone() PrototypeFactory copy = (PrototypeFactory) super.clone(); //In an actual implementation of this pattern you might now change references to //the expensive to produce parts from the copies that are held inside the prototype. return copy; } abstract void prototypeFactory(int x); abstract void printValue(); } /** * Concrete Prototypes to clone */ class PrototypeImpl extends PrototypeFactory { int x; public PrototypeImpl(int x) { this.x = x; } @Override void prototypeFactory(int x) { this.x = x; } public void printValue() { System.out.println("Value :" + x); } } /** * Client Class */ public class PrototypeExample { private PrototypeFactory example; // Could have been a private Cloneable example. public PrototypeExample(PrototypeFactory example) { this.example = example; } public PrototypeFactory makeCopy() throws CloneNotSupportedException { return (PrototypeFactory) this.example.clone(); } public static void main(String args[]) { try { PrototypeFactory tempExample = null; int num = 1000; PrototypeFactory prot = new PrototypeImpl(1000); PrototypeExample cm = new PrototypeExample(prot); for (int i = 0; i < 10; i++) { tempExample = cm.makeCopy(); tempExample.prototypeFactory(i * num); tempExample.printValue(); } } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } /* **Code output** Value :0 Value :1000 Value :2000 Value :3000 Value :4000 Value :5000 Value :6000 Value :7000 Value :8000 Value :9000 */ 生成に関するパターン（英語版）同士には重なる部分があることもある――PrototypeパターンとAbstract Factory パターンのどちらも適切となるような場合もある。また両者が相補的な関係となる場合もある。Abstract Factoryは複製元となる一群のプロトタイプを蓄えておき、生成したオブジェクトを返すようにできる。Abstract Factory、Builder、Prototypeの各パターンは実装の際にSingleton パターンを利用できる。Abstract Factoryのクラスはファクトリメソッド（継承を通す作成）を伴い実装される場合が多いが、プロトタイプ（委譲を通す作成）を用いるように実装することもできる。 デザインはしばしば、比較的に複雑でなく、カスタマイズしやすく、サブクラスを急速に増やすファクトリメソッドを用いるところから出発し、一層の柔軟性が必要となる箇所が発見されるに伴いより柔軟だが複雑なAbstract Factory、Prototype、Builderへと発達してゆく。 プロトタイプはサブクラスの生成を必要としないが、「初期化」の操作を必要とする。ファクトリメソッドはサブクラスの生成を必要とするが、初期化を必要としない。 Composite パターンとDecorator パターンを多用するデザインにおいてもPrototypeパターンはしばしば有用である。 複製しようとしているオブジェクトの「真正なコピー」である別のオブジェクトを「ランタイムに」生成したい場合には、オブジェクトをclone()する必要があるであろうというのが経験則である。「真正なコピー」（True copy）というのは、新規作成されるオブジェクトの全ての属性が複製しようとしているオブジェクトと同一でなければならないという意味である。代わりにnewを用いてクラスから「インスタンス作成」したならば、全ての属性がその初期値となったオブジェクトが得られる。 例えば、銀行口座の取引を行うシステムをデザインしているとすると、口座の情報を保持しているオブジェクトのコピーを作成し、そのコピーに取引を実施し、それからこのコピーで元のオブジェクトを置き換える必要があるであろう。このような場合には、newの代わりにclone()を用いたいであろう。 ^ Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p. 54 ^ GoF, p126 ^ GoF, p81, 134 ^ GoF, p95 ^ GoF, p136 ^ GoF, p116 ^ GoF, p126 Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2.  （脚注GoFのページ番号は原書のもの） エリック・ガンマ、ラルフ・ジョンソン、リチャード・ヘルム、ジョン・ブリシディース（著）、グラディ・ブーチ（まえがき）、本位田真一、吉田和樹（監訳）、『オブジェクト指向における再利用のためのデザインパターン』、ソフトバンクパブリッシング、1995年。ISBN 978-4797311129 関数プロトタイプ Prototype in Source Making Cloneableインターフェース - JavaTM Platform Standard Ed. 6