类的继承和多态

类的继承和多态

欢迎继续本专栏的第十四篇文章。在前几期中,我们已逐步建立了 TypeScript 类的基础知识,包括类的定义、构造函数、属性和方法,以及访问修饰符的运用。这些内容为我们理解面向对象编程的核心原则奠定了基础。今天,我们将深入探讨类的继承和多态这两个关键概念,它们是实现代码复用和灵活设计的强大机制。我们将解释 extends 关键字的使用、方法重写的技巧,以及 super 调用的作用,并通过这些元素展示如何实现代码复用和多态行为。通过由浅入深的讲解、丰富示例和实际场景分析,我们旨在帮助您从基本继承语法逐步掌握高级应用,并在项目中运用这些原则来构建更高效和可扩展的代码结构。内容将从继承的基础概念展开到多态的实践,确保您能获得全面而深刻的洞见。

理解继承和多态在 TypeScript 中的定位

继承(inheritance)是面向对象编程的支柱之一,它允许一个类(子类)从另一个类(父类)获取属性和方法,从而实现代码复用。多态(polymorphism)则基于继承,让不同类的对象以统一方式响应相同消息,实现行为多样性。在 JavaScript 中,继承基于原型链,而 TypeScript 通过类语法和类型系统增强了这一机制,使继承更安全和直观。

继承的定位在于促进"is-a"关系:例如,Dog is-a Animal,这让子类继承父类的通用行为,同时添加特定功能。这减少了重复代码,提高了维护性。多态则允许代码处理父类引用,但执行子类行为,实现"一个接口,多种实现"。在 TypeScript 中,这些概念通过静态类型检查得到强化:编译器确保继承兼容性和方法签名一致,避免运行时意外。

为什么继承和多态重要?在大型项目中,如游戏引擎或企业应用,继承组织层次结构,多态处理变体。根据 TypeScript 的设计,继承与接口结合:类通过 extends 继承,implements 实现接口。这平衡了动态 JS 与静态安全的需要。我们将从 extends 的基本使用开始,逐步引入方法重写、super 调用,并探讨复用和多态的应用,确保您能理解如何避免继承滥用,同时发挥其优势。

继承和多态在 TypeScript 中的历史与 ES6 类同步引入,并在后续版本优化了类型推断。这让它们成为连接过程式和 OOP 的工具,在现代开发中帮助管理复杂状态和行为。

继承的基本语法:extends 关键字的使用

继承使用 extends 关键字,让子类从父类获取成员。子类可访问父类的 public 和 protected 成员,但不包括 private。

extends 的基本定义与简单示例

基础继承:

typescript 复制代码
class Animal {
  name: string;

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

  move(distance: number): void {
    console.log(`${this.name} moved ${distance} meters.`);
  }
}

class Dog extends Animal {
  bark(): void {
    console.log("Woof!");
  }
}

这里,Dog 继承 Animal 的 name、constructor 和 move。创建实例:

typescript 复制代码
const myDog = new Dog("Buddy");
myDog.move(10);  // "Buddy moved 10 meters."
myDog.bark();   // "Woof!"

new Dog 调用 Animal 的构造函数(隐式 super),然后添加 bark。

无构造函数子类:

子类默认调用父类 constructor。

typescript 复制代码
class Cat extends Animal {}  // 继承所有

const myCat = new Cat("Whiskers");
myCat.move(5);  // 有效

基本语法让继承直观,重用父类代码。

extends 的深入机制

多级继承:

typescript 复制代码
class Mammal extends Animal {
  hasFur: boolean = true;
}

class Rabbit extends Mammal {
  jump(): void {
    console.log("Hop!");
  }
}

Rabbit 有 Animal 的 move、Mammal 的 hasFur 和自己的 jump。

静态成员继承:子类继承父类静态。

typescript 复制代码
class Base {
  static count: number = 0;
}

class Derived extends Base {}

console.log(Derived.count);  // 0

深入:extends 要求子类兼容父类类型(协变/逆变规则)。参数类型可更宽,返回更窄。

extends 机制确保类型安全继承,适合建模层次,如 UI 组件基类。

方法重写:自定义子类行为

方法重写(override)允许子类重新定义父类方法,实现特定行为。

方法重写的的基本用法

typescript 复制代码
class Bird extends Animal {
  move(distance: number): void {
    console.log(`${this.name} flew ${distance} meters.`);
  }
}

Bird 重写 move:

typescript 复制代码
const sparrow = new Bird("Tweetie");
sparrow.move(20);  // "Tweetie flew 20 meters."

重写必须签名兼容:参数和返回相同。

方法重写的深入应用

重写 protected 方法:

父类 protected 可在子类重写。

typescript 复制代码
class Vehicle {
  protected startEngine(): void {
    console.log("Engine started.");
  }

  drive(): void {
    this.startEngine();
    console.log("Driving.");
  }
}

class ElectricVehicle extends Vehicle {
  protected startEngine(): void {
    console.log("Battery activated.");
  }
}

ElectricVehicle 重写 startEngine,drive 调用新版。

重写 getter/setter:

typescript 复制代码
class BaseShape {
  get area(): number {
    return 0;
  }
}

class Square extends BaseShape {
  side: number;

  constructor(side: number) {
    super();
    this.side = side;
  }

  get area(): number {
    return this.side ** 2;
  }
}

深入重写让子类定制行为,支持多态(后述)。

风险:重写改变语义导致 bug。实践:文档重写意图。

super 调用:访问父类成员

super 关键字调用父类成员,用于构造函数或方法。

super 在构造函数中的基本用法

子类构造函数必须调用 super() 访问父类初始化。

typescript 复制代码
class Employee extends Person {
  position: string;

  constructor(name: string, age: number, position: string) {
    super(name, age);  // 调用父类 constructor
    this.position = position;
  }
}

无 super 报错。

super 在方法中的深入应用

super 调用父类方法:

typescript 复制代码
class Snake extends Animal {
  move(distance: number): void {
    console.log("Slithering...");
    super.move(distance);  // 调用父类 move
  }
}

Snake.move 先自定义,然后父类行为。

super 在静态:

typescript 复制代码
class Child extends Base {
  static getCount(): number {
    return super.count;  // 访问父静态
  }
}

深入 super 确保继承链完整,结合重写实现增量行为。

应用:日志类,重写 log 调用 super 添加时间戳。

实现代码复用:继承的核心益处

继承通过共享成员实现复用,减少重复。

代码复用的基本示例

基类共享逻辑:

typescript 复制代码
class Logger {
  log(message: string): void {
    console.log(`[INFO] ${message}`);
  }
}

class ErrorLogger extends Logger {
  logError(message: string): void {
    this.log(`Error: ${message}`);
  }
}

ErrorLogger 复用 log 添加错误处理。

代码复用的深入策略

模板方法模式:父类定义框架,子类填充细节。

typescript 复制代码
abstract class Beverage {
  prepare(): void {
    this.boilWater();
    this.brew();
    this.pourInCup();
    this.addCondiments();
  }

  boilWater(): void { console.log("Boiling water"); }
  abstract brew(): void;
  pourInCup(): void { console.log("Pouring into cup"); }
  abstract addCondiments(): void;
}

class Tea extends Beverage {
  brew(): void { console.log("Steeping tea"); }
  addCondiments(): void { console.log("Adding lemon"); }
}

Tea 复用 prepare 框架,定义具体步骤。

复用属性:共享状态管理。

深入复用让代码 DRY,在框架如 Angular 服务继承中常见。

多态行为:统一接口,多样实现

多态让父类引用执行子类行为。

多态的基本示例

typescript 复制代码
function makeAnimalMove(animal: Animal): void {
  animal.move(10);
}

makeAnimalMove(new Dog("Buddy"));  // Dog 的 move
makeAnimalMove(new Bird("Tweetie"));  // Bird 的重写 move

函数用 Animal 类型,但调用子类实现。

多态的深入应用

数组多态:

typescript 复制代码
const animals: Animal[] = [new Dog("Buddy"), new Bird("Tweetie")];
animals.forEach(a => a.move(5));  // 各执行自己 move

策略模式:多态替换 if-else。

typescript 复制代码
interface PaymentStrategy {
  pay(amount: number): void;
}

class CreditCard implements PaymentStrategy {
  pay(amount: number): void { console.log(`Paid ${amount} via credit card`); }
}

class PayPal implements PaymentStrategy {
  pay(amount: number): void { console.log(`Paid ${amount} via PayPal`); }
}

class Checkout {
  constructor(private strategy: PaymentStrategy) {}

  complete(amount: number): void {
    this.strategy.pay(amount);
  }
}

多态让策略可换。

深入多态提升灵活,在插件系统或 UI 渲染中关键。

实际应用:继承与多态在项目中的实践

继承在模型层次:

基类 Entity,子类 User、Product 继承 id、timestamps。

多态在事件处理:基类 EventHandler,子类处理不同事件。

案例:电商系统,Product 基类,Book、Electronics 子类,多态计算价格。

OOP 实践组织代码,易扩展。

高级主题:抽象类与接口结合

抽象类用 abstract,提供部分实现。

如 Beverage 示例。

接口多实现:

类可 implements 多接口,extends 单类。

typescript 复制代码
interface Flyable {
  fly(): void;
}

class FlyingCar extends Car implements Flyable {
  fly(): void { /* ... */ }
}

高级增强继承。

风险与最佳实践

风险:

  • 继承滥用导致紧耦合。
  • 重写破坏 Liskov 替换。
  • super 遗漏初始化错误。

实践:

  • 组合优先继承。
  • 浅继承链。
  • 测试多态。
  • 文档重写。

确保可靠。

案例研究:真实项目

在 React,组件继承共享状态。

在 Node,服务类继承基控制器。

减少冗余 25%。

结语:继承与多态,OOP 的动态力量

通过本篇文章的详尽探讨,您已掌握类的继承和多态,从 extends 到 super。这些原则将助您实现复用和灵活。实践:构建继承 hierarchy。下一期抽象类与接口实现,敬请期待。若疑问,欢迎交流。我们继续。

相关推荐
用户47949283569152 小时前
React 终于出手了:彻底终结 useEffect 的"闭包陷阱"
前端·javascript·react.js
程序员猫哥2 小时前
前端开发,一句话生成网站
前端
Younglina2 小时前
一个纯前端的网站集合管理工具
前端·vue.js·chrome
木头程序员2 小时前
前端(包含HTML/JavaScript/DOM/BOM/jQuery)基础-暴力复习篇
开发语言·前端·javascript·ecmascript·es6·jquery·html5
卖火箭的小男孩2 小时前
# Flutter Provider 状态管理完全指南
前端
小雨青年2 小时前
鸿蒙 HarmonyOS 6|ArkUI(01):从框架认知到项目骨架
前端
信创天地2 小时前
深耕金融政务核心场景:国产化数据库迁移的全流程架构设计与风险管控
运维·网络安全·系统架构·系统安全·运维开发
Null1552 小时前
浏览器唤起本地桌面应用(基础版)
前端·浏览器
哈__2 小时前
React Native 鸿蒙跨平台开发:PixelRatio 实现鸿蒙端图片的高清显示
javascript·react native·react.js