TypeScript 抽象类
TypeScript 抽象类 抽象类(Abstract Class)是 TypeScript 面向对象编程中的重要概念。 它是一种不能被直接实例化的类,只能作为基类供其他类继承。 抽象类主要用于定义子类的公共属性和方法,为子类提供一个统一的结构和行为模板。 抽象类继承层次结构 abstract class Animal 不能直接实例化 clas..
教程详情页默认 noindex。
TypeScript 抽象类
抽象类(Abstract Class)是 TypeScript 面向对象编程中的重要概念。
它是一种不能被直接实例化的类,只能作为基类供其他类继承。
抽象类主要用于定义子类的公共属性和方法,为子类提供一个统一的结构和行为模板。
抽象类继承层次结构 abstract class Animal 不能直接实例化 class Dog extends Animal class Cat extends Animal 抽象类特性 abstract 方法:子类必须实现 具象方法:子类可以直接使用 可作为类型:接收子类实例
为什么需要抽象类
在面向对象编程中,我们经常需要定义一些基类。
这些基类描述了子类共同的属性和方法,但有些方法的实现细节需要由子类自己决定。
抽象类就是用来解决这个问题的:它允许我们定义方法的签名(声明),而把具体实现交给子类。
概念说明:抽象类是一种介于普通类和接口之间的类型。它既有接口的特征(定义方法签名),又有类的特征(可以有具体的方法实现和构造函数)。
抽象类基础
使用 abstract 关键字声明抽象类和抽象方法。
抽象类可以包含抽象方法和具象方法(已有实现的方法)。
实例
// 抽象类不能直接实例化,只能作为基类
abstract class Animal {
// 动物的名字属性
name: string;
// 构造函数
constructor(name: string) {
this.name = name;
}
// 抽象方法:使用 abstract 修饰,没有方法体
// 子类必须实现这个方法
abstract speak(): void;
// 具象方法:有具体实现的方法
// 子类可以直接继承使用,不需要重写
move(): void {
console.log(this.name + " 在移动");
}
}
// 尝试实例化抽象类会报错
// var animal = new Animal("动物"); // 错误:不能实例化抽象类
// 定义 Dog 类继承 Animal
class Dog extends Animal {
// 子类必须实现父类的抽象方法 speak()
speak(): void {
console.log(this.name + " 汪汪汪!");
}
}
// 创建 Dog 实例
var dog = new Dog("旺财");
dog.speak(); // 调用子类实现的方法
dog.move(); // 继承父类的具象方法
运行结果:
旺财 汪汪汪! 旺财 在移动
说明:抽象方法没有方法体(只有方法签名),子类必须实现该方法。具象方法有具体实现,子类可以直接继承使用。
抽象方法
抽象方法是抽象类中只声明但不实现的方法。
子类继承抽象类后,必须实现所有抽象方法,否则会报错。
实例
abstract class Shape {
// 抽象方法:只有声明,没有实现
// 子类必须实现这两个方法
abstract area(): number;
abstract perimeter(): number;
// 具象方法:可以使用抽象方法
// 这个方法调用了抽象方法,子类继承后可以正常使用
describe(): void {
console.log("面积: " + this.area().toFixed(2));
}
}
// 定义矩形类继承 Shape
class Rectangle extends Shape {
// 矩形的宽度
width: number;
// 矩形的高度
height: number;
// 构造函数
constructor(width: number, height: number) {
super(); // 调用父类构造函数
this.width = width;
this.height = height;
}
// 实现抽象方法:计算面积
area(): number {
return this.width * this.height;
}
// 实现抽象方法:计算周长
perimeter(): number {
return 2 * (this.width + this.height);
}
}
// 创建矩形实例
var rect = new Rectangle(4, 5);
// 调用继承的 describe 方法,内部会调用子类的 area 方法
rect.describe();
console.log("周长: " + rect.perimeter());
运行结果:
面积: 20.00 周长: 18
提示:具象方法可以调用抽象方法。这是因为当具象方法被调用时,子类已经实现了抽象方法,所以可以正常执行。
抽象类作为类型
抽象类可以作为参数类型使用。
这意味着函数可以接受任何抽象类的子类实例,实现了多态。
实例
abstract class Animal {
// 抽象方法:所有动物都会发出声音
abstract speak(): void;
}
// 定义 Cat 类继承 Animal
class Cat extends Animal {
// 实现抽象方法
speak(): void {
console.log("喵喵喵!");
}
}
// 定义 Dog 类继承 Animal
class Dog extends Animal {
// 实现抽象方法
speak(): void {
console.log("汪汪汪!");
}
}
// 定义函数参数类型为抽象类 Animal
// 这个函数可以接受任何 Animal 的子类实例
function makeSpeak(animal: Animal): void {
animal.speak();
}
// 传入不同的子类实例,实现不同的行为(多态)
makeSpeak(new Cat());
makeSpeak(new Dog());
// 抽象类类型数组:可以存储不同子类实例
var animals: Animal[] = [new Cat(), new Dog()];
运行结果:
喵喵喵! 汪汪汪!
多态:抽象类作为类型时,实际执行的是子类的方法实现。这就是面向对象的多态特性。
抽象类与接口的区别
抽象类和接口都用于定义类型规范,但有一些关键区别。
理解它们的差异有助于在实际开发中做出正确的选择。
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 实例化 | 不能直接实例化 | 不能直接实例化 |
| 方法实现 | 可以有具体实现 | 只能有声明(TypeScript 3.6+ 可有默认实现) |
| 成员修饰符 | 可以添加 public、protected、private | 只能有 readonly |
| 继承 | 单继承(只能 extends 一个类) | 多实现(可以 implements 多个接口) |
| 构造函数 | 可以有构造函数 | 不能有构造函数 |
选择建议:需要共享代码使用(用抽象类);需要定义规范/契约(用接口);需要多继承(用接口)。
完整示例:支付系统
下面是一个使用抽象类实现的支付系统示例。
这个示例展示了抽象类在实际项目中的应用。
实例
abstract class Payment {
// 抽象方法:处理支付,子类必须实现
abstract process(amount: number): boolean;
// 具象方法:验证支付信息
// 所有子类都可以使用这个方法
validate(): void {
console.log("验证支付信息");
}
}
// 信用卡支付类
class CreditCardPayment extends Payment {
// 信用卡号码
cardNumber: string;
// 构造函数
constructor(cardNumber: string) {
super(); // 调用父类构造函数
this.cardNumber = cardNumber;
}
// 实现抽象方法:处理信用卡支付
process(amount: number): boolean {
console.log("处理信用卡支付: " + amount);
return true;
}
}
// PayPal 支付类
class PayPalPayment extends Payment {
// PayPal 邮箱
email: string;
// 构造函数
constructor(email: string) {
super();
this.email = email;
}
// 实现抽象方法:处理 PayPal 支付
process(amount: number): boolean {
console.log("处理 PayPal 支付: " + amount);
return true;
}
}
// 使用多态处理不同的支付方式
var payments: Payment[] = [
new CreditCardPayment("1234"),
new PayPalPayment("[email protected]")
];
// 遍历处理每种支付方式
for (var _i = 0, payments_1 = payments; _i < payments_1.length; _i++) {
var payment = payments_1[_i];
// 调用继承的验证方法
payment.validate();
// 调用子类的处理方法
payment.process(100);
}
运行结果:
验证支付信息 处理信用卡支付: 100 验证支付信息 处理 PayPal 支付: 100
应用场景:抽象类常用于框架设计和业务逻辑分层。例如支付处理、用户认证、数据持久化等场景。
注意事项
- 不能实例化:抽象类不能直接使用 new 创建实例,必须通过子类继承
- 必须实现抽象方法:子类如果不实现所有抽象方法,会报错
- 可以有构造函数:抽象类可以定义构造函数,子类需要调用 super()
- 单继承:一个类只能继承一个抽象类(单继承)
- 访问修饰符:抽象方法可以使用 public、protected 修饰符
最佳实践:当多个类需要共享代码和逻辑时,使用抽象类。当只需要定义规范和契约时,使用接口。
总结
抽象类是 TypeScript 面向对象编程的重要组成部分。
- abstract 关键字:用于声明抽象类和方法
- 不能实例化:只能通过子类继承使用
- 抽象方法:子类必须实现的方法
- 具象方法:子类可以直接继承使用的有实现的方法
- 模板方法模式:抽象类定义骨架,子类提供具体实现
建议:在设计类层次结构时,优先考虑使用抽象类来共享代码和定义规范。