如何基于Key调用功能相同实现不同的类?规避if/else与冗余实例化
解决方案与技术解析
核心优化思路
针对提前实例化浪费资源、分支代码冗余的问题,核心解决方向是抽象统一契约+延迟初始化+集中管理类的创建逻辑,既符合DRY原则,又能按需实例化对象。
具体实现步骤
1. 定义统一接口(类型约束)
先通过TypeScript接口定义所有类必须遵守的方法契约,避免any带来的类型不安全问题:
interface NumProvider { getNum(): number; }
让所有业务类实现这个接口:
class MyClass1 implements NumProvider { public getNum(): number { return 1; } } class MyClass2 implements NumProvider { public getNum(): number { return 2; } } // 其余8个类同样实现NumProvider接口
2. 实现带缓存的延迟初始化工厂类
用映射表存储类的构造函数而非提前实例化的对象,仅在调用时创建实例并缓存(避免重复实例化):
class NumFactory { // 存储key与对应类构造函数的映射 private classMap: Record<string, new () => NumProvider> = { keyA: MyClass1, keyB: MyClass2, // 补充剩余8个key和类的映射 }; // 缓存已实例化的对象 private instanceCache: Record<string, NumProvider> = {}; getNum(key: string): number { // 检查缓存,无则实例化 if (!this.instanceCache[key]) { const Constructor = this.classMap[key]; if (!Constructor) { throw new Error(`未找到对应key的实现类: ${key}`); } this.instanceCache[key] = new Constructor(); } return this.instanceCache[key].getNum(); } }
3. 使用示例
const numFactory = new NumFactory(); // 第一次调用keyA时才实例化MyClass1 console.log(numFactory.getNum('keyA')); // 输出1 // 第一次调用keyB时才实例化MyClass2 console.log(numFactory.getNum('keyB')); // 输出2 // 再次调用keyA直接复用缓存的实例 console.log(numFactory.getNum('keyA')); // 输出1
可选:无缓存的瞬时实例版本
如果不需要复用实例(每次调用都创建新对象),可以去掉缓存逻辑:
class TransientNumFactory { private classMap: Record<string, new () => NumProvider> = { keyA: MyClass1, keyB: MyClass2, }; getNum(key: string): number { const Constructor = this.classMap[key]; if (!Constructor) { throw new Error(`未找到对应key的实现类: ${key}`); } return new Constructor().getNum(); } }
相关技术术语(便于自学)
- 接口抽象:通过接口定义统一行为契约,强制所有实现类遵循相同方法签名,提升代码可维护性与类型安全性。
- 延迟初始化(Lazy Initialization):仅在对象被实际使用时才完成实例化,避免提前创建未使用的对象,节省内存与初始化资源。
- 工厂模式(Factory Pattern):通过集中的工厂类管理对象创建逻辑,替代分散的
if...else/switch分支,降低调用方与具体类的耦合,符合DRY原则。 - 依赖倒置原则(Dependency Inversion Principle):调用方依赖抽象接口而非具体实现类,后续新增实现类时无需修改现有调用逻辑,扩展更灵活。
内容的提问来源于stack exchange,提问作者angryserver
相关产品推荐
相关产品推荐

