抽象类是不能被直接实例化的类,它作为其他类的基类使用。抽象类可以包含抽象方法,子类必须实现这些方法。抽象类是定义通用接口和共享实现的理想方式。
使用 abstract 关键字定义抽象类。抽象类不能使用 new 直接实例化。
abstract class Animal {
name: string
constructor(name: string) {
this.name = name
}
abstract speak(): void
move(): void {
console.log(`${this.name} 移动`)
}
}
class Dog extends Animal {
speak(): void {
console.log(`${this.name} 汪汪叫`)
}
}
const dog = new Dog("小黑")
dog.speak()
dog.move()
Animal 是抽象类,定义了抽象方法 speak 和具体方法 move。Dog 继承 Animal 并实现了 speak 方法。尝试直接创建 Animal 实例会报错。
抽象方法只有签名没有实现,子类必须提供具体实现。
abstract class Shape {
abstract getArea(): number
abstract getPerimeter(): number
describe(): string {
return `面积: ${this.getArea()}, 周长: ${this.getPerimeter()}`
}
}
class Rectangle extends Shape {
constructor(
public width: number,
public height: number
) {
super()
}
getArea(): number {
return this.width * this.height
}
getPerimeter(): number {
return 2 * (this.width + this.height)
}
}
class Circle extends Shape {
constructor(public radius: number) {
super()
}
getArea(): number {
return Math.PI * this.radius * this.radius
}
getPerimeter(): number {
return 2 * Math.PI * this.radius
}
}
const rect = new Rectangle(10, 20)
const circle = new Circle(5)
console.log(rect.describe())
console.log(circle.describe())
Shape 定义了两个抽象方法,子类 Rectangle 和 Circle 各自实现了计算逻辑。describe 方法在抽象类中提供通用实现,子类可以直接使用。
抽象类可以定义抽象属性,子类必须实现这些属性。
abstract class Entity {
abstract id: number
abstract createdAt: Date
getAge(): number {
return Date.now() - this.createdAt.getTime()
}
}
class User extends Entity {
id: number
createdAt: Date
name: string
constructor(id: number, name: string) {
super()
this.id = id
this.name = name
this.createdAt = new Date()
}
}
const user = new User(1, "张三")
console.log(user.id)
console.log(user.name)
console.log(user.getAge())
id 和 createdAt 是抽象属性,User 类必须定义这些属性。
抽象类和接口都可以定义契约,但有一些重要区别。
interface IAnimal {
name: string
speak(): void
}
abstract class AnimalBase {
name: string
constructor(name: string) {
this.name = name
}
abstract speak(): void
move(): void {
console.log(`${this.name} 移动`)
}
}
class Cat1 implements IAnimal {
name: string
constructor(name: string) {
this.name = name
}
speak(): void {
console.log(`${this.name} 喵喵叫`)
}
}
class Cat2 extends AnimalBase {
constructor(name: string) {
super(name)
}
speak(): void {
console.log(`${this.name} 喵喵叫`)
}
}
主要区别:
抽象类常用于实现模板方法模式,在抽象类中定义算法骨架,子类实现具体步骤。
abstract class DataParser {
parse(filePath: string): any {
const content = this.readFile(filePath)
const data = this.parseContent(content)
const validated = this.validate(data)
return this.transform(validated)
}
protected readFile(filePath: string): string {
console.log(`读取文件: ${filePath}`)
return "文件内容"
}
protected abstract parseContent(content: string): any
protected validate(data: any): any {
console.log("验证数据")
return data
}
protected transform(data: any): any {
console.log("转换数据")
return data
}
}
class JsonParser extends DataParser {
protected parseContent(content: string): any {
console.log("解析 JSON")
return JSON.parse(content || "{}")
}
}
class XmlParser extends DataParser {
protected parseContent(content: string): any {
console.log("解析 XML")
return { parsed: "xml" }
}
}
const jsonParser = new JsonParser()
const xmlParser = new XmlParser()
jsonParser.parse("data.json")
xmlParser.parse("data.xml")
parse 方法定义了处理流程,子类只需要实现 parseContent 方法。这种模式让代码结构清晰,也便于扩展新的解析器。
抽象类可以作为类型使用,用于标注变量的类型。
abstract class Component {
abstract render(): string
}
class Button extends Component {
render(): string {
return "<button>点击</button>"
}
}
class Input extends Component {
render(): string {
return "<input type='text' />"
}
}
function renderPage(components: Component[]): string {
return components.map(c => c.render()).join("\n")
}
const page = renderPage([
new Button(),
new Input(),
new Button()
])
console.log(page)
Component 作为类型标注参数,任何继承 Component 的类都可以传入。
抽象类可以继承另一个抽象类,可以保持或实现父类的抽象成员。
abstract class Vehicle {
abstract move(): void
}
abstract class MotorVehicle extends Vehicle {
engineRunning: boolean = false
startEngine(): void {
this.engineRunning = true
console.log("引擎启动")
}
stopEngine(): void {
this.engineRunning = false
console.log("引擎停止")
}
}
class Car extends MotorVehicle {
move(): void {
if (!this.engineRunning) {
this.startEngine()
}
console.log("汽车行驶")
}
}
const car = new Car()
car.move()
car.stopEngine()
MotorVehicle 继承 Vehicle 但没有实现 move 方法,仍然是抽象类。Car 继承 MotorVehicle 并实现了 move 方法。
抽象类在实际开发中有很多应用场景,比如定义基础控制器:
abstract class BaseController {
protected abstract getModel(): string
async index(): Promise<string> {
return `获取 ${this.getModel()} 列表`
}
async show(id: number): Promise<string> {
return `获取 ${this.getModel()} ID: ${id}`
}
async store(data: any): Promise<string> {
console.log("验证数据:", data)
return `创建 ${this.getModel()}`
}
async update(id: number, data: any): Promise<string> {
console.log("验证数据:", data)
return `更新 ${this.getModel()} ID: ${id}`
}
async destroy(id: number): Promise<string> {
return `删除 ${this.getModel()} ID: ${id}`
}
}
class UserController extends BaseController {
protected getModel(): string {
return "用户"
}
}
const userController = new UserController()
console.log(userController.index())
console.log(userController.show(1))
console.log(userController.store({ name: "张三" }))
基础控制器定义了通用的 CRUD 操作,子类只需要指定模型名称。
抽象类是不能实例化的类,用于定义子类的通用模板。它可以包含抽象方法和具体实现,子类必须实现所有抽象成员。抽象类适合定义"是什么"的关系,提供代码复用和类型约束。合理使用抽象类可以构建清晰的类层次结构,提高代码的可维护性。