原型模式
约 803 字
原型模式
核心思想
原型模式允许通过复制已有实例来生成新实例,而无需依赖其所属的类。
典型用例
状态复制
使用原型模式可以有效地进行状态复制,尤其是在实现撤销/重做功能或需要保存和恢复对象状态的场景中。通过原型模式,可以轻松地保存对象的当前状态,并在需要时恢复这些状态。
通过使用克隆方法,可以在任何时候保存对象的当前状态,并在以后需要时恢复这些状态。
通过原型模式,可以避免直接与对象的内部状态交互,而是通过克隆和恢复状态来管理这些状态,这样做更安全且更易于维护。
// npm run code src/code/design-pattern/prototype/state-replication.ts
export {};
interface Prototype {
clone(): Prototype;
}
class StatefulObject implements Prototype {
private state: any;
constructor(state?: any) {
this.state = state;
}
setState(state: any): void {
this.state = state;
}
getState(): any {
return this.state;
}
clone(): this {
// 提供深拷贝,以确保状态对象的复制
const cloned = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
cloned.state = JSON.parse(JSON.stringify(this.state));
return cloned;
}
}
function main() {
const original = new StatefulObject();
original.setState({ x: 10, y: 20 });
// 保存当前状态
const savedState = original.clone();
// 更改状态
original.setState({ x: 15, y: 25 });
console.log(original.getState()); // 输出: { x: 15, y: 25 }
// 恢复之前的状态
original.setState(savedState.getState());
console.log(original.getState()); // 输出: { x: 10, y: 20 }
}
main();
复制复杂对象
当创建一个对象的成本比较高时,例如:复杂的计算或数据库查询,可以通过复制一个已经创建的对象来提高效率。
在这个例子中,通过一个 clone 方法可以创建一个新实例,而无需再次经历昂贵的创建过程。这种方式在需要大量类似对象,且每个对象的创建成本都很高时非常有用。
// npm run code src/code/design-pattern/prototype/copy-object.ts
export {};
// 定义一个原型接口,包含一个克隆方法
interface Prototype {
clone(): Prototype;
}
// 具体原型类
class ComplexObject implements Prototype {
private data: number[];
constructor(data?: number[]) {
if (data) {
// 通过克隆创建对象时,直接使用提供的数据
console.log("Cheap clone process");
this.data = data;
} else {
// 首次创建对象时,执行高成本操作
console.log("Expensive creation process");
this.data = this.expensiveInitialization();
}
}
private expensiveInitialization(): number[] {
// 这里模拟一些成本高昂的操作
return [1, 2, 3]; // 模拟复杂数据
}
clone(): Prototype {
// 使用现有数据创建一个新对象,避免重复高成本操作
return new ComplexObject([...this.data]);
}
}
const original = new ComplexObject(); // 创建一个原型实例
const clone = original.clone(); // 克隆原型实例,避免重复高成本的初始化
console.log("Original:", original);
console.log("Clone:", clone);
避免子类过多
当系统中对象的类别太多,导致类的数量过多时,可以使用原型模式来避免子类的膨胀。
原型模式可以在原型接口中定义一个克隆方法,由具体的类实现对象的拷贝,而无需再创建新的子类。
// npm run code src/code/design-pattern/prototype/avoid-subclassing.ts
export {};
interface Prototype {
clone(): Prototype;
}
class ConcretePrototype implements Prototype {
public field: string;
constructor(field: string) {
this.field = field;
}
clone(): this {
// 创建当前对象的浅拷贝。对于更复杂的情况,可能需要深拷贝。
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
function main() {
const prototype = new ConcretePrototype("value1");
const clonedPrototype = prototype.clone();
console.log(prototype.field); // 输出: value1
console.log(clonedPrototype.field); // 输出: value1
console.log(prototype === clonedPrototype); // 输出: false,因为它们是不同的实例
}
main();
动态加载或生成对象
使用原型模式进行动态加载或生成对象,可以有效地减少系统对具体类的依赖,从而提高系统的灵活性和可扩展性。原型模式通过复制现有对象来创建新对象,而不是通过调用构造函数。这样可以在运行时动态地生成对象,而不需要知道对象的具体类型。
在这个例子中,原型注册类用于管理原型实例。可以在系统初始化时注册一些原型,然后在运行时根据需要从注册表中检索并克隆这些原型。这种方法避免了直接依赖具体的类,提高了代码的灵活性和可维护性。
// npm run code src/code/design-pattern/prototype/dynamically-generate-objects.ts
export {};
interface Prototype {
clone(): Prototype;
}
class ConcretePrototypeA implements Prototype {
clone(): this {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
class ConcretePrototypeB implements Prototype {
clone(): this {
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
class PrototypeRegistry {
private prototypes = new Map<string, Prototype>();
registerPrototype(name: string, prototype: Prototype): void {
this.prototypes.set(name, prototype);
}
getPrototype(name: string): Prototype | undefined {
const prototype = this.prototypes.get(name);
return prototype ? prototype.clone() : undefined;
}
}
function main() {
const registry = new PrototypeRegistry();
// 注册原型
registry.registerPrototype("PrototypeA", new ConcretePrototypeA());
registry.registerPrototype("PrototypeB", new ConcretePrototypeB());
// 根据需要动态创建对象
const prototypeA = registry.getPrototype("PrototypeA");
const prototypeB = registry.getPrototype("PrototypeB");
console.log(prototypeA instanceof ConcretePrototypeA); // 输出: true
console.log(prototypeB instanceof ConcretePrototypeB); // 输出: true
}
main();
初始化复杂对象
原型模式可以非常有效地用于复制初始化过程复杂的对象。当对象的构造过程涉及多个步骤并且相对成本较高时,使用原型模式可以简化这个过程。可以先创建并初始化一个原型对象,然后每次需要新实例时,只需复制这个已初始化的原型,而不是重新走完整的构造过程。
// npm run code src/code/design-pattern/prototype/initial-complex-objects.ts
export {};
interface Prototype {
clone(): Prototype;
}
class ComplexObject implements Prototype {
private partA: string;
private partB: string;
private partC: string;
constructor() {
// 初始化可能是一个复杂的过程
this.partA = 'Initialization of Part A';
this.partB = 'Initialization of Part B';
this.partC = 'Initialization of Part C';
}
// 示例方法,用于显示状态
showState(): void {
console.log(`Part A: ${this.partA}, Part B: ${this.partB}, Part C: ${this.partC}`);
}
clone(): this {
// 提供一个深拷贝
return Object.assign(Object.create(Object.getPrototypeOf(this)), this);
}
}
function main() {
// 创建并初始化原型实例
const prototype = new ComplexObject();
prototype.showState(); // 显示初始状态
// 使用原型复制来创建新实例,而不需要重新初始化
const clone1 = prototype.clone();
const clone2 = prototype.clone();
// 显示克隆对象的状态,确认它们已经被正确初始化
clone1.showState();
clone2.showState();
}
main();