TypeScript:如何在抽象类中实现创建自身实例的逻辑
解决不可变Enemy类hit方法逻辑复用问题
你需要将子类重复的hit逻辑抽至抽象父类,但TypeScript不允许父类直接创建子类实例,以下是三种可行方案:
方案一:抽象工厂方法(推荐,符合开闭原则)
在抽象类中定义一个抽象的实例创建方法,由子类实现自身实例的创建逻辑,父类的hit方法调用该方法完成逻辑复用:
abstract class Enemy { abstract readonly attackPower: number; constructor( public readonly health: number ) { } // 子类需实现该方法,返回自身类型的新实例 protected abstract create(health: number): this; hit(): this { return this.create(this.health - 1); } } class Boss extends Enemy { attackPower = 100; protected create(health: number): Boss { return new Boss(health); } } class NormalEnemy extends Enemy { attackPower = 5; protected create(health: number): NormalEnemy { return new NormalEnemy(health); } }
该方案扩展性强,新增Enemy子类时只需实现create方法,无需修改父类代码。
方案二:构造函数类型断言
直接通过this.constructor获取当前实例的构造函数,结合类型断言创建新实例:
abstract class Enemy { abstract readonly attackPower: number; constructor( public readonly health: number ) { } hit(): this { // 断言构造函数接收number参数并返回当前类型实例 const Constructor = this.constructor as new (health: number) => this; return new Constructor(this.health - 1); } } class Boss extends Enemy { attackPower = 100; } class NormalEnemy extends Enemy { attackPower = 5; }
该方案代码简洁,但要求所有子类构造函数仅接收health一个参数,否则会出现运行时错误。
方案三:泛型约束抽象类
通过泛型参数绑定子类类型,明确构造函数的返回类型:
abstract class Enemy<T extends Enemy<T>> { abstract readonly attackPower: number; constructor( public readonly health: number ) { } hit(): T { const Constructor = this.constructor as new (health: number) => T; return new Constructor(this.health - 1); } } class Boss extends Enemy<Boss> { attackPower = 100; } class NormalEnemy extends Enemy<NormalEnemy> { attackPower = 5; }
该方案类型约束更严谨,子类需显式指定泛型参数,确保返回类型准确。
内容的提问来源于stack exchange,提问作者Yahya Uddin
相关产品推荐
相关产品推荐

