You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何枚举实现IShape接口的类并支持扩展

嗨,这个需求刚好是开闭原则的典型应用场景!咱们可以用「注册表模式」来实现,让所有实现IShape的类自动注册到统一容器里,后续新增形状完全不用动原有代码。下面一步步拆解给你看:

实现方案:基于注册表的自动扩展模式

1. 先定义核心的IShape接口

把基础的接口规范先定好,确保所有形状类都遵循统一的方法约定:

interface IShape {
  // 返回形状的友好名称
  GetName(): string;
  // 执行绘制逻辑
  Draw(): void;
}

2. 创建形状注册表

我们需要一个全局容器来存放所有IShape的构造函数,同时提供注册方法让形状类主动“报到”:

// 定义形状构造函数的类型,确保传入的类符合IShape接口规范
type ShapeConstructor = new () => IShape;

// 注册表容器,存放所有已注册的形状类
const shapeRegistry: ShapeConstructor[] = [];

// 注册函数,供每个形状类调用完成注册
function registerShape(ctor: ShapeConstructor) {
  shapeRegistry.push(ctor);
}

3. 实现基础形状类并自动注册

接下来实现Rectangle、Circle这些类,每个类定义完成后,直接调用registerShape把自己加入注册表——完全不用手动维护硬编码的列表:

class Rectangle implements IShape {
  GetName(): string {
    return "矩形";
  }

  Draw(): void {
    console.log("绘制矩形:🟩");
  }
}
// 自动注册到注册表
registerShape(Rectangle);

class Circle implements IShape {
  GetName(): string {
    return "圆形";
  }

  Draw(): void {
    console.log("绘制圆形:🔵");
  }
}
registerShape(Circle);

class Triangle implements IShape {
  GetName(): string {
    return "三角形";
  }

  Draw(): void {
    console.log("绘制三角形:🔺");
  }
}
registerShape(Triangle);

4. 生成下拉选项并处理用户选择

现在可以直接从注册表中取出所有形状类,动态生成下拉选项;用户选中后,实例化对应类并调用Draw方法:

// 动态渲染形状下拉菜单的示例函数
function renderShapeDropdown() {
  const select = document.createElement("select");
  
  // 遍历注册表,逐个添加下拉选项
  shapeRegistry.forEach((ShapeCtor) => {
    const shapeInstance = new ShapeCtor();
    const option = document.createElement("option");
    option.value = ShapeCtor.name; // 用类名作为选项标识(可根据需求替换为自定义ID)
    option.textContent = shapeInstance.GetName();
    select.appendChild(option);
  });

  // 绑定选择事件,触发绘制逻辑
  select.addEventListener("change", (e) => {
    const selectedCtorName = (e.target as HTMLSelectElement).value;
    // 从注册表中找到对应的形状构造函数
    const selectedShapeCtor = shapeRegistry.find(ctor => ctor.name === selectedCtorName);
    if (selectedShapeCtor) {
      const shape = new selectedShapeCtor();
      shape.Draw();
    }
  });

  // 将下拉菜单添加到页面中
  document.body.appendChild(select);
}

// 调用渲染函数生成下拉菜单
renderShapeDropdown();

5. 新增形状的扩展方式

现在要加Square、Oval这类新形状,只需要实现IShape接口,然后调用registerShape就行——完全不用修改之前的注册表、下拉渲染代码:

class Square implements IShape {
  GetName(): string {
    return "正方形";
  }

  Draw(): void {
    console.log("绘制正方形:🟦");
  }
}
registerShape(Square);

class Oval implements IShape {
  GetName(): string {
    return "椭圆形";
  }

  Draw(): void {
    console.log("绘制椭圆形:🥚");
  }
}
registerShape(Oval);

额外优化小建议

  • 如果担心代码压缩后类名被混淆,可以给每个形状类加一个静态的shapeId属性,用这个作为唯一标识(代替ctor.name):
    class Rectangle implements IShape {
      static shapeId = "rectangle";
      // ... 其他代码
    }
    // 注册和查找时改用shapeId
    
  • 可以把注册表和注册函数封装成单例类,避免全局变量污染,更符合面向对象的设计风格。

内容的提问来源于stack exchange,提问作者Hugo Bernier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:20:57