原型模式核心概念

  1. 原型模式 (Prototype Pattern)
    1. 通过复制 (克隆) 已有对象 (原型) 来创建新对象,而非通过构造函数重新初始化;
    2. 这种方式可以避免重复创建相似对象的开销,尤其适合创建复杂对象、对象初始化成本高的场景;
  2. 类图:
  3. 实现代码:
    /**
     * 1. 抽象原型接口(定义克隆规范)
     */
    interface Prototype {
      clone(): Prototype;
    }
    
    /**
     * 2. 具体原型类(核心:clone 方法不调用构造函数,直接复制原型)
     */
    class UserPrototype implements Prototype {
      public name: string;
      public age: number;
      public preferences: { theme: string; fontSize: number };
    
      /**
       * 仅用于创建「原型对象」的构造函数(只执行一次)
       * @param name 用户名
       * @param age 年龄
       * @param preferences 偏好设置
       */
      constructor(name: string, age: number, preferences: { theme: string; fontSize: number }) {
        this.name = name;
        this.age = age;
        this.preferences = preferences;
        console.log("构造函数仅执行一次(原型对象创建时)");
      }
    
      /**
       * 克隆方法(核心改进:不调用 new UserPrototype(),直接复制原型)
       * 用 Object.create 继承原型的属性,再深拷贝引用类型,避免共享
       * @returns 新的 UserPrototype 实例
       */
      clone(): UserPrototype {
        // 步骤1:创建一个空对象,原型指向当前实例(继承所有属性)
        const clone = Object.create(this);
        // 步骤2:深拷贝引用类型属性(避免和原型共享)
        clone.preferences = { ...this.preferences };
        // 步骤3:返回克隆对象(全程未调用构造函数)
        return clone;
      }
    
      setPreferences(preferences: { theme: string; fontSize: number }) {
        this.preferences = preferences;
      }
    }
    
    // ---------------------- 测试代码 ----------------------
    // 1. 创建原型对象(仅这一步调用构造函数)
    const userPrototype = new UserPrototype("张三", 25, { theme: "dark", fontSize: 16 });
    // 输出:构造函数仅执行一次(原型对象创建时)
    
    // 2. 克隆新对象(核心:不调用构造函数)
    const user1 = userPrototype.clone();
    const user2 = userPrototype.clone();
    // 控制台不会再输出构造函数的日志 → 证明未调用构造函数
    
    // 3. 修改新实例的属性(验证深克隆:引用类型属性互不影响)
    user1.name = "李四";
    user1.preferences.theme = "light";
    
    user2.age = 30;
    user2.preferences.fontSize = 18;
    
    // 输出结果验证
    console.log("原型实例:", userPrototype); 
    // 原型实例: { name: '张三', age: 25, preferences: { theme: 'dark', fontSize: 16 } }
    console.log("克隆实例1:", user1); 
    // 克隆实例1: { name: '李四', age: 25, preferences: { theme: 'light', fontSize: 16 } }
    console.log("克隆实例2:", user2); 
    // 克隆实例2: { name: '张三', age: 30, preferences: { theme: 'dark', fontSize: 18 } }
    
    // 验证引用类型是否独立(深克隆生效)
    console.log(user1.preferences === userPrototype.preferences); // false
    

原型模式的常用场景

批量创建相似对象(如列表数据)

  1. 当需要生成大量结构相似的对象 (如表格数据、模拟数据) 时,克隆原型对象比重复 new 更高效:
    // 列表项原型
    const listItemPrototype = {
      id: 0,
      title: "",
      status: "pending",
      createTime: new Date()
    };
    
    // 批量生成列表数据(克隆原型)
    function generateListData(count: number) {
      return Array.from({ length: count }, (_, index) => {
        const clonedItem = { ...listItemPrototype }; // 克隆原型
        clonedItem.id = index + 1;
        clonedItem.title = `任务${index + 1}`;
        clonedItem.createTime = new Date(Date.now() - index * 86400000);
        return clonedItem;
      });
    }
    
    // 生成 10 条列表数据
    const listData = generateListData(10);
    

数据模拟

  1. canvas 数据生成,原型模式生成小球;
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>原型模式 - 动态圆形</title>
        <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
    
            canvas {
                display: block; /* 消除默认边距 */
            }
        </style>
    </head>
    <body>
        <canvas id="canvas" width="1000" height="300"></canvas>
    
        <script>
            // 封装成独立模块,避免全局变量污染
            (function () {
                // ========== 工具函数(优化) ==========
                /**
                 * 生成随机十六进制颜色(非递归版,性能更优)
                 * @returns {string} 十六进制颜色值
                 */
                const getRandomColor = () => {
                    const color = Math.floor(Math.random() * 0xFFFFFF)
                        .toString(16)
                        .padStart(6, '0'); // 补零,避免递归
                    return `#${color}`;
                };
    
                // ========== 原型模式核心:圆形原型类 ==========
                class CirclePrototype {
                    /**
                     * 原型构造函数(仅初始化一次原型属性)
                     * @param {number} defaultRadius 默认半径
                     */
                    constructor(defaultRadius = 30) {
                        this.defaultRadius = defaultRadius;
                        this.x = 0;
                        this.y = 0;
                        this.radius = defaultRadius;
                    }
    
                    /**
                     * 原型克隆方法(核心:创建新实例,复用原型逻辑)
                     * @param {number} x 横坐标
                     * @param {number} y 纵坐标
                     * @returns {CirclePrototype} 克隆的新圆形实例
                     */
                    clone(x, y) {
                        const circle = Object.create(this); // 继承原型方法/属性
                        circle.x = x;
                        circle.y = y;
                        circle.radius = this.defaultRadius; // 复用原型默认半径
                        return circle;
                    }
    
                    /**
                     * 更新圆形状态(半径递减)
                     * @returns {boolean} 是否需要继续渲染
                     */
                    update() {
                        this.radius = Math.max(0, this.radius - 1); // 避免半径为负
                        return this.radius > 0;
                    }
    
                    /**
                     * 渲染圆形(复用原型渲染逻辑)
                     * @param {CanvasRenderingContext2D} ctx Canvas 上下文
                     */
                    render(ctx) {
                        ctx.beginPath();
                        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
                        ctx.fillStyle = getRandomColor();
                        ctx.fill();
                        ctx.closePath(); // 闭合路径,优化绘制性能
                    }
                }
    
                // ========== 初始化逻辑 ==========
                const init = () => {
                    // 获取 Canvas 元素和上下文
                    const canvas = document.getElementById('canvas');
                    const ctx = canvas.getContext('2d');
                    if (!ctx) return;
    
                    // 1. 创建圆形原型对象(仅创建一次,后续都克隆它)
                    const circlePrototype = new CirclePrototype(30);
    
                    // 2. 存储活跃的圆形实例(替代原全局数组)
                    let activeCircles = [];
    
                    // 3. 鼠标移动事件:克隆原型生成新圆形
                    canvas.addEventListener('mousemove', (event) => {
                        // 核心:通过克隆原型创建新圆形,而非 new Circle()
                        const newCircle = circlePrototype.clone(
                            event.clientX,
                            event.clientY
                        );
                        activeCircles.push(newCircle);
                    });
    
                    // 4. 动画循环(用 requestAnimationFrame 替代 setInterval,更流畅)
                    const animate = () => {
                        // 清空画布
                        ctx.clearRect(0, 0, canvas.width, canvas.height);
    
                        // 过滤并更新/渲染圆形(优化:一次遍历完成过滤+渲染)
                        activeCircles = activeCircles.filter(circle => {
                            const isAlive = circle.update();
                            if (isAlive) {
                                circle.render(ctx);
                            }
                            return isAlive;
                        });
    
                        requestAnimationFrame(animate); // 持续动画
                    };
    
                    // 启动动画
                    animate();
                };
    
                // 页面加载完成后初始化
                window.addEventListener('DOMContentLoaded', init);
            })();
        </script>
    </body>
    </html>
    
  2. 演示:

*图表/表单配置复用

原型模式的优缺点

  1. 优点:
    1. 性能提升:避免重复执行复杂的初始化过程;
    2. 减少子类构造:无需创建大量的工厂类;
    3. 动态配置:可以在运行时添加和移除原型;
    4. 简化创建:隐藏了对象创建的复杂性;
  2. 缺点:
    1. 克隆复杂:需要正确处理循环引用和深拷贝;
    2. 继承问题:如果类已经有继承关系,实现克隆可能变得复杂;
    3. 接口设计:所有子类都必须实现克隆方法;

最佳实践建议

  1. 明确克隆类型:根据需求选择浅拷贝或深拷贝;
  2. 使用原型注册表:管理常用原型对象;
  3. 注意引用类型:确保克隆时正确处理数组、对象等引用类型;
  4. 实现 Cloneable 接口:使用 TypeScript 接口强制实现克隆方法;
  5. 考虑使用序列化:对于复杂对象,可以考虑使用 JSON 序列化实现深拷贝;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 原型模式核心概念
  2. 2. 原型模式的常用场景
    1. 2.1. 批量创建相似对象(如列表数据)
    2. 2.2. 数据模拟
    3. 2.3. *图表/表单配置复用
  3. 3. 原型模式的优缺点
  4. 4. 最佳实践建议