![Prototype](/images/patterns/cards/prototype-mini.png?id=bc3046bb39ff36574c08d49839fd1c8e)
Prototype を TypeScript で
Prototype は、 生成に関するデザインパターンの一つで、 特定のクラスに結合することなく、 オブジェクト (たとえ複雑なオブジェクトでも) のクローン作成を可能とします。
プロトタイプのクラス全部には、 共通するインターフェースが必要です。 これにより、 具象クラスが不明であってもオブジェクトを複製することが可能となります。 プロトタイプ・オブジェクトが、 完全なコピーを生成できるのは、 同じクラスのオブジェクト同士が非公開フィールドを互いにアクセスできるからです。
複雑度:
人気度:
使用例: Prototype パターンは、 TypeScript では、 JavaScript の生来のメソッドである Object.assign()
を使って、 初めから利用可能です。
見つけ方: このパターンは、 clone
や copy
といったメソッドで容易に識別可能です。
概念的な例
この例は、 Prototype デザインパターンの構造を説明するためのものです。 以下の質問に答えることを目的としています:
- どういうクラスからできているか?
- それぞれのクラスの役割は?
- パターンの要素同士はどう関係しているのか?
index.ts: 概念的な例
/**
* The example class that has cloning ability. We'll see how the values of field
* with different types will be cloned.
*/
class Prototype {
public primitive: any;
public component: object;
public circularReference: ComponentWithBackReference;
public clone(): this {
const clone = Object.create(this);
clone.component = Object.create(this.component);
// Cloning an object that has a nested object with backreference
// requires special treatment. After the cloning is completed, the
// nested object should point to the cloned object, instead of the
// original object. Spread operator can be handy for this case.
clone.circularReference = {
...this.circularReference,
prototype: { ...this },
};
return clone;
}
}
class ComponentWithBackReference {
public prototype;
constructor(prototype: Prototype) {
this.prototype = prototype;
}
}
/**
* The client code.
*/
function clientCode() {
const p1 = new Prototype();
p1.primitive = 245;
p1.component = new Date();
p1.circularReference = new ComponentWithBackReference(p1);
const p2 = p1.clone();
if (p1.primitive === p2.primitive) {
console.log('Primitive field values have been carried over to a clone. Yay!');
} else {
console.log('Primitive field values have not been copied. Booo!');
}
if (p1.component === p2.component) {
console.log('Simple component has not been cloned. Booo!');
} else {
console.log('Simple component has been cloned. Yay!');
}
if (p1.circularReference === p2.circularReference) {
console.log('Component with back reference has not been cloned. Booo!');
} else {
console.log('Component with back reference has been cloned. Yay!');
}
if (p1.circularReference.prototype === p2.circularReference.prototype) {
console.log('Component with back reference is linked to original object. Booo!');
} else {
console.log('Component with back reference is linked to the clone. Yay!');
}
}
clientCode();
Output.txt: 実行結果
Primitive field values have been carried over to a clone. Yay!
Simple component has been cloned. Yay!
Component with back reference has been cloned. Yay!
Component with back reference is linked to the clone. Yay!