混入简介
本课属于 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 没有继承关系,但它们都需要游泳行为。使用混入,你只需编写一次代码,就能在需要的地方共享它。
挑战
简单让我们构建一个乐器系统,展示混入如何让互不相关的类共享行为。你将创建一个提供调音功能的混入,然后将它应用于不同的乐器类,这些类之间没有继承关系。
你将把代码分成两个文件:
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()
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器