Menu
CoddyTech

多态基础

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 57 课,共 110 课。

多态的意思是“多种形式”,指的是通过共同的接口处理不同类的对象的能力。当你有一个父类引用时,它可以指向任何子类对象,并根据对象的实际类型调用正确的方法。

这很强大,因为你可以编写与父类类型配合的代码,而它会自动正确处理所有子类类型:

class Animal {
  void speak() => print('Some sound');
}

class Dog extends Animal {
  @override
  void speak() => print('Woof!');
}

class Cat extends Animal {
  @override
  void speak() => print('Meow!');
}

void main() {
  Animal myPet = Dog();  // 父类类型,子类对象
  myPet.speak();  // 输出:Woof!
  
  myPet = Cat();  // 同一个变量,不同的对象
  myPet.speak();  // 输出:Meow!
}

变量 myPet 声明为 Animal,但它保存的是 Dog 或 Cat。调用 speak() 时,Dart 会在运行时查看对象的实际类型,并调用相应的重写方法。

这样你就能编写适用于任何子类的灵活函数:

void makeAllSpeak(List<Animal> animals) {
  for (var animal in animals) {
    animal.speak();  // 每只动物都用自己的方式叫
  }
}

void main() {
  var pets = [Dog(), Cat(), Dog()];
  makeAllSpeak(pets);
  // 输出:Woof! Meow! Woof!
}

这个函数不需要了解 Dog 或 Cat,它只需处理 Animal。这样,你的代码更容易扩展,因为添加新的动物类型不需要修改现有函数。

challenge icon

挑战

简单

让我们构建一个乐器系统,展示多态的实际应用。你将创建一个基类 Instrument 和几种乐器类型,然后编写一个函数,让任意一组乐器一起演奏,无需知道它们的具体类型。

你将把代码分成两个文件:

  • instruments.dart:在这里定义乐器层次结构:
    • 一个 Instrument 类,包含一个 String name 属性和一个构造函数。添加一个方法 play(),用于打印 [name] makes a sound
    • 一个继承 Instrument 的 Guitar 类,并重写 play(),使其打印 [name] strums melodically
    • 一个继承 Instrument 的 Drum 类,并重写 play(),使其打印 [name] beats rhythmically
    • 一个继承 Instrument 的 Piano 类,并重写 play(),使其打印 [name] plays harmoniously
    此外,创建一个函数 performConcert(List<Instrument> instruments),打印 Concert begins!,然后遍历列表并对每种乐器调用 play(),最后打印 Concert ends!
  • main.dart:导入乐器文件,并创建一支混合乐队来展示多态:
    • 创建一个类型为 List<Instrument> 的列表,其中包含一把名为 'Acoustic' 的 Guitar、一面名为 'Snare' 的 Drum,以及一架名为 'Grand' 的 Piano
    • 将这个列表传给 performConcert()

注意,performConcert() 使用父类型 Instrument,但每种乐器都以自己独特的方式演奏。这就是多态:同一个方法调用会根据对象的实际类型产生不同的行为。

预期输出:

Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!

亲手试试

import 'instruments.dart';

void main() {
  // TODO: 创建一个 List<Instrument>,其中包含:
  // - 一个名为 'Acoustic' 的 Guitar
  // - 一个名为 'Snare' 的 Drum
  // - 一个名为 'Grand' 的 Piano
  
  
  // TODO: 将你的乐器列表传给 performConcert() 并调用它
  
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器