TypeScript中基于工厂函数的工厂类与单例工厂类继承实现问题咨询
你的核心需求是实现一个继承自Factory的单例工厂类,问题出在对TypeScript中类的方法与实例属性的访问规则理解上。我来一步步拆解问题,然后给出可行的解决方案:
为什么你的代码会报错?
第一个版本的错误原因
在最初的代码里,Factory类的make是一个实例属性(类型为函数),而不是类的原型方法。当你在SingletonFactory里尝试用super.make()调用父类的逻辑时,TypeScript的规则是:super关键字只能用来访问父类的原型方法(public/protected),无法直接访问父类的实例属性,所以会抛出Only public and protected methods of the base class are accessible via the 'super' keyword的错误。
第二个版本的错误原因
你尝试把make声明成方法,但又在构造函数里给this.make赋值,这就造成了冲突:TypeScript认为你要么定义一个方法(需要有实现体),要么定义一个实例属性,但不能同时声明方法的签名又给实例属性赋值,于是报错Function implementation is missing or not immediately following the declaration。
正确的实现方案
方案一:将make定义为类的原型方法
这是最符合面向对象设计的方案,把创建逻辑封装在父类的方法中,子类通过super.make()调用父类的创建逻辑:
type FactoryFunction<T> = () => T; export class Factory<T> { // 把传入的工厂函数存在私有属性中 private readonly factory: FactoryFunction<T>; constructor(factory: FactoryFunction<T>) { this.factory = factory; } // 定义为类的public方法,子类可以通过super访问 public make(): T { return this.factory(); } } export class SingletonFactory<T> extends Factory<T> { // 用可选类型避免初始化时的赋值问题 private instance?: T; constructor(factory: FactoryFunction<T>) { super(factory); } // 使用override关键字明确重写父类方法(TypeScript 4.3+支持) public override make(): T { if (!this.instance) { // 现在可以正确调用父类的make方法创建实例 this.instance = super.make(); } return this.instance; } }
方案二:封装受保护的创建方法(保留实例属性风格)
如果你更倾向于把make作为实例属性(比如用箭头函数绑定this),可以把核心的创建逻辑封装成父类的protected方法,子类直接调用这个方法:
type FactoryFunction<T> = () => T; export class Factory<T> { private readonly factory: FactoryFunction<T>; constructor(factory: FactoryFunction<T>) { this.factory = factory; } // 受保护的方法,子类可以访问 protected createInstance(): T { return this.factory(); } // make作为实例属性 public make = (): T => { return this.createInstance(); }; } export class SingletonFactory<T> extends Factory<T> { private instance?: T; constructor(factory: FactoryFunction<T>) { super(factory); } // 重写make属性 public override make = (): T => { if (!this.instance) { // 调用父类的受保护方法创建实例 this.instance = this.createInstance(); } return this.instance; }; }
验证使用方式
两种方案都可以正常使用,比如:
// 创建一个普通工厂 const normalFactory = new Factory(() => ({ id: Math.random() })); console.log(normalFactory.make() !== normalFactory.make()); // true,每次创建新实例 // 创建单例工厂 const singletonFactory = new SingletonFactory(() => ({ id: Math.random() })); console.log(singletonFactory.make() === singletonFactory.make()); // true,始终返回同一个实例
内容的提问来源于stack exchange,提问作者Rafael Arantes

