跳至主要內容

原型模式

约 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();

上次编辑于: