抽象类 (Abstract Classes)
抽象类是 TypeScript 和面向对象编程中的一个重要概念。它们用于定义一个基类,该基类可以包含具体的方法和属性,也可以包含没有实现的抽象方法。抽象类不能被直接实例化,只能被继承,这使得它们非常适合用于定义接口或提供部分实现。
1. 基本概念
- 抽象类:使用
abstract关键字声明的类,不能被直接实例化。 - 抽象方法:在抽象类中声明但未实现的方法,子类必须实现这些方法。
- 部分实现:抽象类可以包含具体的方法和属性,为子类提供通用的实现逻辑。
2. 语法
定义抽象类
typescript
abstract class Animal {
// 抽象方法,必须在子类中实现
abstract makeSound(): void;
// 具体方法,可以在子类中重写
move(): void {
console.log("Moving...");
}
}在这个例子中,Animal 是一个抽象类,它包含一个抽象方法 makeSound 和一个具体方法 move。
继承抽象类
typescript
class Dog extends Animal {
makeSound(): void {
console.log("Barking");
}
}
const dog = new Dog();
dog.makeSound(); // 输出: Barking
dog.move(); // 输出: Moving...在这个例子中,Dog 类继承了 Animal 类,并实现了抽象方法 makeSound。由于 Animal 是抽象类,不能直接创建 Animal 的实例,但可以创建 Dog 的实例。
3. 示例解析
示例 1: 基本用法
typescript
abstract class Vehicle {
constructor(public brand: string) {}
// 抽象方法,必须在子类中实现
abstract start(): void;
// 具体方法,可以在子类中重写
stop(): void {
console.log(`${this.brand} has stopped.`);
}
}
class Car extends Vehicle {
start(): void {
console.log(`${this.brand} car is starting.`);
}
override stop(): void {
console.log(`${this.brand} car has stopped.`);
}
}
// const vehicle = new Vehicle("Generic"); // 错误:不能实例化抽象类
const car = new Car("Toyota");
car.start(); // 输出: Toyota car is starting.
car.stop(); // 输出: Toyota car has stopped.在这个例子中,Vehicle 是一个抽象类,它有一个抽象方法 start 和一个具体方法 stop。Car 类继承了 Vehicle 并实现了 start 方法。尝试直接实例化 Vehicle 类会导致编译错误。
示例 2: 多个抽象方法
typescript
abstract class Shape {
abstract getArea(): number;
abstract getPerimeter(): number;
printInfo() {
console.log(`Area: ${this.getArea()}, Perimeter: ${this.getPerimeter()}`);
}
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) {
super();
}
getArea(): number {
return this.width * this.height;
}
getPerimeter(): number {
return 2 * (this.width + this.height);
}
}
const rectangle = new Rectangle(5, 10);
rectangle.printInfo(); // 输出: Area: 50, Perimeter: 30在这个例子中,Shape 是一个抽象类,它有两个抽象方法 getArea 和 getPerimeter。Rectangle 类继承了 Shape 并实现了这两个方法。printInfo 方法是一个具体方法,可以在不重写的情况下直接使用。
示例 3: 抽象类中的构造函数
typescript
abstract class Base {
protected name: string;
constructor(name: string) {
this.name = name;
}
abstract greet(): void;
}
class Derived extends Base {
constructor(name: string, public age: number) {
super(name); // 必须调用父类的构造函数
}
greet(): void {
console.log(
`Hello, my name is ${this.name} and I am ${this.age} years old.`
);
}
}
const derived = new Derived("Alice", 30);
derived.greet(); // 输出: Hello, my name is Alice and I am 30 years old.在这个例子中,Base 是一个抽象类,它有一个受保护的属性 name 和一个抽象方法 greet。Derived 类继承了 Base,并实现了 greet 方法。注意,Derived 类的构造函数必须调用 super 来初始化父类。
4. 应用场景
- 定义接口:抽象类可以用来定义一组方法和属性,强制子类实现这些方法,类似于接口的作用,但可以包含部分实现。
- 提供默认实现:抽象类可以为常用功能提供默认实现,减少代码重复。
- 层次结构:抽象类适合用于定义层次化的类结构,例如几何形状、车辆等。
5. 注意事项
- 不能实例化:抽象类不能被直接实例化,只能通过继承来使用。
- 必须实现抽象方法:如果子类继承了抽象类,则必须实现所有的抽象方法,除非子类本身也是抽象类。
- 可以包含具体方法:抽象类可以包含具体的方法和属性,为子类提供通用的实现逻辑。
- 构造函数:子类的构造函数必须调用父类的构造函数(使用
super),以确保正确初始化父类的状态。
6. 总结
抽象类是 TypeScript 中非常有用的特性,它们允许你定义不能直接实例化的基类,并要求子类实现特定的方法。通过合理使用抽象类,你可以提高代码的可维护性和灵活性,同时保持类型安全。