Skip to content

抽象类 (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 和一个具体方法 stopCar 类继承了 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 是一个抽象类,它有两个抽象方法 getAreagetPerimeterRectangle 类继承了 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 和一个抽象方法 greetDerived 类继承了 Base,并实现了 greet 方法。注意,Derived 类的构造函数必须调用 super 来初始化父类。

4. 应用场景

  • 定义接口:抽象类可以用来定义一组方法和属性,强制子类实现这些方法,类似于接口的作用,但可以包含部分实现。
  • 提供默认实现:抽象类可以为常用功能提供默认实现,减少代码重复。
  • 层次结构:抽象类适合用于定义层次化的类结构,例如几何形状、车辆等。

5. 注意事项

  • 不能实例化:抽象类不能被直接实例化,只能通过继承来使用。
  • 必须实现抽象方法:如果子类继承了抽象类,则必须实现所有的抽象方法,除非子类本身也是抽象类。
  • 可以包含具体方法:抽象类可以包含具体的方法和属性,为子类提供通用的实现逻辑。
  • 构造函数:子类的构造函数必须调用父类的构造函数(使用 super),以确保正确初始化父类的状态。

6. 总结

抽象类是 TypeScript 中非常有用的特性,它们允许你定义不能直接实例化的基类,并要求子类实现特定的方法。通过合理使用抽象类,你可以提高代码的可维护性和灵活性,同时保持类型安全。

Released under the MIT License.