TypeScript根据类型动态生成类实例 消除多if-else的实现方案
实现方案
完全可以通过**工厂注册表(映射表)**模式替代多分支if/else判断,这也是工厂策略模式在TypeScript中的标准落地方式,实现后新增产品类型无需修改工厂函数核心逻辑,符合开闭原则。
首先先修正原有代码的类型定义问题:原代码中type字段使用宽泛的string类型,无法做合法值校验,先和数据库枚举对齐定义严格的类型约束:
// 和数据库存储的枚举值一一对应 type ProductType = 'prod1' | 'prod2' | 'prod3'; interface Product { readonly type: ProductType; name(): string; } class Product1 implements Product { readonly type = 'prod1' as const; name() { return 'Product 1'; } } class Product2 implements Product { readonly type = 'prod2' as const; name() { return 'Product 2'; } } class Product3 implements Product { readonly type = 'prod3' as const; name() { return 'Product 3'; } }
基础实现:手动维护映射表
核心思路是提前建立「产品类型值 -> 对应类构造函数」的键值映射,工厂函数直接通过key取到构造函数实例化即可,不需要任何分支判断:
// 类型到类构造函数的注册表 const productRegistry: Record<ProductType, new () => Product> = { prod1: Product1, prod2: Product2, prod3: Product3 }; function getProductByType(type: ProductType): Product { const ProductConstructor = productRegistry[type]; // 可选:增加非法类型兜底校验 if (!ProductConstructor) { throw new Error(`无效的产品类型:${type}`); } return new ProductConstructor(); }
该方案的优势:
- 无冗余分支判断,代码简洁可维护
- TypeScript会自动校验注册表是否覆盖了所有合法的ProductType取值,漏写、错写键值会直接报类型错误
- 后续新增产品类型(比如prod4),只需要新建对应Product类,在注册表中新增一行键值对即可,不需要修改工厂函数逻辑
如果产品类需要传入构造参数,只需要调整注册表的构造函数类型定义即可,比如构造需要传入商品ID参数时,将构造函数类型改为new (id: string) => Product,实例化时传入对应参数即可。
进阶实现:装饰器自动注册
如果产品类型较多,不想手动维护注册表,可以通过类装饰器实现类定义时自动完成注册,进一步减少重复代码:
// 全局注册表 const productRegistry: Record<ProductType, new () => Product> = {} as any; // 产品注册装饰器 function RegisterProduct(type: ProductType) { return function (ProductCtor: new () => Product) { productRegistry[type] = ProductCtor; }; } // 类定义时加装饰器即可自动完成注册,无需手动修改注册表 @RegisterProduct('prod1') class Product1 implements Product { readonly type = 'prod1' as const; name() { return 'Product 1'; } } @RegisterProduct('prod2') class Product2 implements Product { readonly type = 'prod2' as const; name() { return 'Product 2'; } } @RegisterProduct('prod3') class Product3 implements Product { readonly type = 'prod3' as const; name() { return 'Product 3'; } } // 工厂函数逻辑和之前完全一致 function getProductByType(type: ProductType): Product { const ProductConstructor = productRegistry[type]; if (!ProductConstructor) { throw new Error(`无效的产品类型:${type}`); } return new ProductConstructor(); }
内容的提问来源于stack exchange,提问作者Jean DuPont
相关产品推荐
相关产品推荐

