TypeScript - Abstract Classes

Здравствуйте,野心勃勃的程序员们!今天,我们将踏上一段激动人心的旅程,探索TypeScript的世界,并了解其强大的特性之一:抽象类。如果你是编程新手,不用担心;我会一步一步地引导你了解这个概念,就像我多年来教导无数学生一样。那么,让我们开始吧!

TypeScript - Abstract Classes

什么是抽象类?

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

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

创建抽象类

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

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

抽象方法

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

具体方法

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

示例 1:Shape 抽象类

让我们创建一个简单的示例来说明抽象类是如何工作的。我们将创建一个抽象的Shape类,其中有一个抽象方法calculateArea()

abstract class Shape {
    color: string;

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

    abstract calculateArea(): number;

    displayColor(): void {
        console.log(`This shape is ${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("red", 5);
console.log(circle.calculateArea()); // 输出: 78.53981633974483
circle.displayColor(); // 输出: This shape is red

const rectangle = new Rectangle("blue", 4, 6);
console.log(rectangle.calculateArea()); // 输出: 24
rectangle.displayColor(); // 输出: This shape is blue

在这个示例中,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} moved ${distance} meters.`);
    }
}

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

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

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

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

让我们使用这些类:

const dog = new Dog("Buddy");
dog.makeSound(); // 输出: Woof! Woof!
dog.move(10); // 输出: Buddy moved 10 meters.

const cat = new Cat("Whiskers");
cat.makeSound(); // 输出: Meow!
cat.move(5); // 输出: Whiskers moved 5 meters.

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

为什么使用抽象类?

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

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

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

抽象类中的方法

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

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

结论

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

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

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

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

Credits: Image by storyset