TypeScript - 抽象类

你好,有抱负的程序员们!今天,我们将踏上一段激动人心的旅程,探索TypeScript的世界,并深入了解其强大的特性之一:抽象类。如果你是编程新手,不用担心;我会一步步引导你理解这个概念,就像我多年来教导无数学生一样。那么,让我们开始吧!

TypeScript - Abstract Classes

什么是抽象类?

在我们深入了解抽象类之前,先用一个简单的类比来理解。想象你在一个汽车经销商那里,看到了一个写着“车辆”的标志。现在,你实际上不能购买一个“车辆”,因为它太宽泛了。你需要选择一种具体的车辆类型,比如汽车、卡车或摩托车。在编程中,抽象类就像是那个一般的“车辆”概念 - 它是其他类的蓝图,但你不能直接从中创建一个对象。

TypeScript中的抽象类作为其他类可以继承的基类。它们可能包含抽象方法(没有主体的方法)和具体方法(有主体的方法)。要记住的关键点是,你不能直接创建抽象类的实例。

创建抽象类

现在,让我们看看如何在TypeScript中创建一个抽象类。我们在class关键字之前使用abstract关键字。以下是一个基本结构:

abstract class 类名 {
// 属性和方法放在这里
}

抽象方法

抽象类可以有抽象方法。这些是声明了但没有在抽象类中实现的方法。任何扩展此抽象类的类都必须为这些方法提供实现。

具体方法

抽象类也可以有具体方法,这些是完整实现的方法,可以被子类继承。

示例 1:Shape 抽象类

让我们创建一个简单的示例来演示抽象类的工作方式。我们将创建一个抽象的Shape类,它有一个抽象方法calculateArea()

abstract class Shape {
color: string;

constructor(color: string) {
this.color = color;
}

abstract calculateArea(): number;

displayColor(): void {
console.log(`这个形状的颜色是 ${this.color}`);
}
}

在这个示例中:

  • Shape是我们的抽象类。
  • color是所有形状都将有的属性。
  • calculateArea()是抽象方法。注意它没有主体,只有声明。
  • displayColor()是一个具体方法,所有形状都可以使用。

现在,让我们创建一些扩展我们的Shape类的具体形状:

class Circle extends Shape {
radius: number;

constructor(color: string, radius: number) {
super(color);
this.radius = radius;
}

calculateArea(): number {
return Math.PI * this.radius * this.radius;
}
}

class Rectangle extends Shape {
width: number;
height: number;

constructor(color: string, width: number, height: number) {
super(color);
this.width = width;
this.height = height;
}

calculateArea(): number {
return this.width * this.height;
}
}

现在我们可以使用这些类:

const circle = new Circle("红色", 5);
console.log(circle.calculateArea()); // 输出: 78.53981633974483
circle.displayColor(); // 输出: 这个形状的颜色是 红色

const rectangle = new Rectangle("蓝色", 4, 6);
console.log(rectangle.calculateArea()); // 输出: 24
rectangle.displayColor(); // 输出: 这个形状的颜色是 蓝色

在这个示例中,CircleRectangle都扩展了Shape类,并提供了calculateArea()方法的自己的实现。它们还从Shape类继承了displayColor()方法。

示例 2:Animal 抽象类

让我们再创建一个示例来加强我们的理解。这次,我们将创建一个抽象的Animal类:

abstract class Animal {
name: string;

constructor(name: string) {
this.name = name;
}

abstract makeSound(): void;

move(distance: number = 0): void {
console.log(`${this.name} 移动了 ${distance} 米。`);
}
}

class Dog extends Animal {
constructor(name: string) {
super(name);
}

makeSound(): void {
console.log("汪!汪!");
}
}

class Cat extends Animal {
constructor(name: string) {
super(name);
}

makeSound(): void {
console.log("喵!");
}
}

让我们使用这些类:

const dog = new Dog("Buddy");
dog.makeSound(); // 输出: 汪!汪!
dog.move(10); // 输出: Buddy 移动了 10 米。

const cat = new Cat("Whiskers");
cat.makeSound(); // 输出: 喵!
cat.move(5); // 输出: Whiskers 移动了 5 米。

在这个示例中,Animal是我们的抽象类,它有一个抽象的makeSound()方法和一个具体的方法move()DogCat扩展了Animal并提供了makeSound()方法的自己的实现。

为什么使用抽象类?

你可能会想,“为什么要这么麻烦?为什么不直接使用普通类?” 嗯,抽象类在你想要为一系列相关类定义一个公共接口时非常有用。它们允许你:

  1. 为一组相关类定义一个共同的结构。
  2. 强制子类实现某些方法。
  3. 提供所有子类都可以使用的一些公共功能。

把它看作是创建一个模板或合同,其他类必须遵循。这是确保相关类之间一致性的方式,同时仍然允许在需要时进行定制。

抽象类中的方法

下面是一个总结抽象类中可以有哪些类型的方法的表格:

方法类型 描述 可以在抽象类上调用吗? 子类必须实现吗?
抽象方法 声明但没有实现
具体方法 完全实现的方法 否(可以被覆盖)

结论

好了,各位!我们已经穿越了TypeScript中抽象类的领域。从理解它们是什么,到创建它们,再到用真实世界的示例看到它们的作用,你现在对这个强大的TypeScript特性有了坚实的基础。

记住,抽象类就像是建筑的蓝图。它们提供了结构和一些细节,但是扩展它们的类需要填充具体细节并将它们变为现实。

在你继续编程之旅时,你会发现抽象类是你TypeScript工具箱中非常有用的工具。它们帮助你编写更干净、更有组织、更易于维护的代码。所以,大胆地去抽象吧!

快乐编码,下次见,继续探索和学习!

Credits: Image by storyset