Menu
CoddyTech

混入简介

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

你已经学过,Dart 只允许继承一个类。虽然你可以实现多个接口,但所有代码都必须自己编写。如果你想在多个互不相关的类之间共享实际的实现代码,该怎么办?这时就要用到 混入。

混入是一种在多个类层次结构中复用代码的方式。你可以把它看作一组方法和属性,可以“混入”任何类中,让类获得新的能力,而无需使用继承。

mixin Swimming {
  void swim() {
    print('Swimming through the water');
  }
}

class Duck with Swimming {
  void quack() {
    print('Quack!');
  }
}

class Fish with Swimming {
  void blowBubbles() {
    print('Blub blub');
  }
}

void main() {
  var duck = Duck();
  duck.quack();
  duck.swim();  // 来自 mixin
  
  var fish = Fish();
  fish.swim();  // 实现相同,类不同
}

注意 with 关键字,这是将混入应用到类的方式。与 implements 不同,你不需要自己编写方法。混入会提供实际的代码,你的类会自动获得相应的功能。

混入解决了一个实际问题:Duck 和 Fish 没有继承关系,但它们都需要游泳行为。使用混入,你只需编写一次代码,就能在需要的地方共享它。

challenge icon

挑战

简单

让我们构建一个乐器系统,展示混入如何让互不相关的类共享行为。你将创建一个提供调音功能的混入,然后将它应用于不同的乐器类,这些类之间没有继承关系。

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

  • instruments.dart:在这里定义混入和乐器类:
    • 一个 Tunable 混入,其中包含一个会打印 Tuning the instrument... 的方法 tune(),以及一个会打印 Tuning is perfect! 的方法 checkTuning()
    • 一个使用 Tunable 混入的 Guitar 类。添加一个带构造函数的 String brand 属性。包含一个会打印 [brand] guitar strumming chords 的方法 strum()
    • 一个同样使用 Tunable 混入的 Piano 类。添加一个带构造函数的 int keys 属性。包含一个会打印 Playing [keys]-key piano 的方法 play()
  • main.dart:导入乐器文件,并演示这两种互不相关的乐器如何通过同一个混入获得调音功能:
    • 创建一个品牌为 'Fender' 的 Guitar
    • 创建一台有 88 个琴键的 Piano
    • 对于吉他:先调用 tune(),然后调用 strum(),最后调用 checkTuning()
    • 打印一个空行
    • 对于钢琴:先调用 tune(),然后调用 play(),最后调用 checkTuning()

注意,Guitar 和 Piano 是完全不同的乐器,它们之间没有继承关系,却都能从 Tunable 混入中获得完全相同的调音方法。你只需编写一次调音代码,这两个类就都能通过 with 关键字使用它。

预期输出:

Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!

Tuning the instrument...
Playing 88-key piano
Tuning is perfect!

亲手试试

import 'instruments.dart';

void main() {
  // TODO:创建一个品牌为 'Fender' 的 Guitar
  
  // TODO:创建一个有 88 个琴键的 Piano
  
  // TODO:对吉他依次调用 tune()、strum() 和 checkTuning()
  
  // TODO:打印一个空行
  
  // TODO:对钢琴依次调用 tune()、play() 和 checkTuning()
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器