当前位置:  首页>> 技术小册>> TypeScript开发实战

11 | 类(2):抽象类与多态

在TypeScript(及面向对象编程的广泛语境中),类(Class)是构建软件系统的基石,它封装了数据(属性)和操作这些数据的方法。随着软件复杂度的提升,仅仅使用基本的类结构往往不足以满足设计需求,这时,抽象类(Abstract Class)和多态(Polymorphism)便成为了解决复杂问题、提高代码复用性和灵活性的重要工具。本章将深入探讨TypeScript中的抽象类与多态概念,并通过实例展示它们在实际开发中的应用。

11.1 抽象类:定义与特性

11.1.1 抽象类的基本概念

抽象类是一种特殊的类,它不能被实例化(即不能直接创建对象)。抽象类的主要目的是为其他类提供一个公共的接口规范,确保子类遵循特定的结构或行为模式。在TypeScript中,使用abstract关键字来声明一个抽象类或方法。

11.1.2 抽象方法的定义

抽象方法是只有方法签名而没有具体实现的方法。它必须在非抽象子类中实现。抽象方法只能存在于抽象类中,且抽象类至少包含一个抽象方法。

  1. abstract class Animal {
  2. abstract makeSound(): void; // 抽象方法
  3. }
  4. // 错误:不能实例化抽象类
  5. // let myAnimal = new Animal();
  6. class Dog extends Animal {
  7. makeSound(): void {
  8. console.log('Woof!');
  9. }
  10. }
  11. let myDog = new Dog();
  12. myDog.makeSound(); // 输出:Woof!

11.1.3 抽象类的其他成员

除了抽象方法外,抽象类还可以包含非抽象方法、属性、构造函数等。这些成员可以被直接访问或继承。

  1. abstract class Animal {
  2. name: string;
  3. constructor(name: string) {
  4. this.name = name;
  5. }
  6. abstract makeSound(): void;
  7. greet(): void {
  8. console.log(`Hello, I am ${this.name}.`);
  9. }
  10. }
  11. class Cat extends Animal {
  12. makeSound(): void {
  13. console.log('Meow!');
  14. }
  15. }
  16. let myCat = new Cat('Kitty');
  17. myCat.greet(); // 输出:Hello, I am Kitty.
  18. myCat.makeSound(); // 输出:Meow!

11.2 多态:概念与实践

11.2.1 多态的基本概念

多态(Polymorphism)是面向对象编程中的一个核心概念,意指“多种形态”。它允许我们以统一的接口处理不同类型的对象,使得同一操作作用于不同的对象上可以有不同的解释,产生不同的执行结果。多态增强了软件的扩展性和可维护性。

11.2.2 实现多态的两种方式

  1. 接口实现多态:通过定义接口,让不同的类实现同一接口,从而实现多态。

    1. interface Animal {
    2. makeSound(): void;
    3. }
    4. class Dog implements Animal {
    5. makeSound(): void {
    6. console.log('Woof!');
    7. }
    8. }
    9. class Cat implements Animal {
    10. makeSound(): void {
    11. console.log('Meow!');
    12. }
    13. }
    14. function makeItSound(animal: Animal): void {
    15. animal.makeSound();
    16. }
    17. makeItSound(new Dog()); // 输出:Woof!
    18. makeItSound(new Cat()); // 输出:Meow!
  2. 抽象类实现多态:虽然抽象类本身不能直接实例化,但它通过定义抽象方法和非抽象成员,为子类提供了一个统一的模板,子类通过继承并实现抽象方法,达到多态的效果。

    1. abstract class Animal {
    2. abstract makeSound(): void;
    3. }
    4. class Dog extends Animal {
    5. makeSound(): void {
    6. console.log('Woof!');
    7. }
    8. }
    9. class Cat extends Animal {
    10. makeSound(): void {
    11. console.log('Meow!');
    12. }
    13. }
    14. // 假设我们有一个统一的调用函数
    15. function makeAnimalSound(animal: Animal): void {
    16. if (animal instanceof Animal) {
    17. animal.makeSound();
    18. }
    19. }
    20. makeAnimalSound(new Dog()); // 输出:Woof!
    21. makeAnimalSound(new Cat()); // 输出:Meow!

11.2.3 多态的优势

  • 提高代码的扩展性:当需要添加新的类时,只需确保它实现了相应的接口或继承了抽象类,并实现了必要的方法,就可以轻松地将其集成到现有的系统中。
  • 提高代码的可维护性:通过定义统一的接口或抽象类,可以清晰地规定类的行为,减少因类间耦合过紧而导致的维护困难。
  • 增强代码的复用性:多态允许我们编写与特定类型无关的代码,这些代码可以应用于任何实现了特定接口或继承了特定抽象类的对象上。

11.3 实战应用:使用抽象类与多态构建动物王国

假设我们需要构建一个模拟动物王国的系统,其中包含多种动物,每种动物都有自己独特的声音。我们可以使用抽象类和多态来实现这一需求。

首先,定义一个抽象类Animal,它包含一个抽象方法makeSound,用于表示动物的叫声。

  1. abstract class Animal {
  2. name: string;
  3. constructor(name: string) {
  4. this.name = name;
  5. }
  6. abstract makeSound(): void;
  7. greet(): void {
  8. console.log(`Hello, I am ${this.name}.`);
  9. }
  10. }

然后,创建几个具体的动物类,如DogCatBird,它们继承自Animal类并实现makeSound方法。

  1. class Dog extends Animal {
  2. makeSound(): void {
  3. console.log(`${this.name} says Woof!`);
  4. }
  5. }
  6. class Cat extends Animal {
  7. makeSound(): void {
  8. console.log(`${this.name} says Meow!`);
  9. }
  10. }
  11. class Bird extends Animal {
  12. makeSound(): void {
  13. console.log(`${this.name} sings Tweet!`);
  14. }
  15. }

最后,我们可以编写一个函数来展示不同动物的叫声,这个函数接受任何Animal类型的对象作为参数。

  1. function showAnimalSound(animal: Animal): void {
  2. animal.greet();
  3. animal.makeSound();
  4. }
  5. let myDog = new Dog('Buddy');
  6. let myCat = new Cat('Whiskers');
  7. let myBird = new Bird('Tweety');
  8. showAnimalSound(myDog);
  9. showAnimalSound(myCat);
  10. showAnimalSound(myBird);

通过这种方式,我们构建了一个灵活且可扩展的动物王国系统,能够轻松地添加新的动物种类而无需修改现有的代码结构。这正是抽象类与多态在实际开发中的强大之处。


该分类下的相关小册推荐: