混入与继承
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 54 课,共 110 课。
现在你已经学会了混入的工作原理,接下来我们来说明什么时候应该使用混入,而不是继承。关键区别在于它们所表达的关系。
继承表示一种“is-a”关系。Dog是一种Animal。子类是父类的专门版本,而且你只能扩展一个类。
另一方面,混入表示一种“能做”的关系。Dog 可以游泳,但游泳并不是狗的定义特征。
// 继承:Dog 是一种 Animal
class Animal {
String name;
Animal(this.name);
}
class Dog extends Animal {
Dog(String name) : super(name);
}
// 混入:Dog 可以游泳(但游泳并不能定义 Dog)
mixin Swimming {
void swim() => print('Swimming');
}
class Dog extends Animal with Swimming {
Dog(String name) : super(name);
}当类具有共同的基本身份,并且你需要在父类中定义构造函数时,使用继承。当你想为没有共同祖先的类添加能力时,使用混入。
| 特性 | 继承 | 混入 |
|---|---|---|
| 关系 | 是一种 | 可以做 |
| 限制 | 只能有一个父类 | 可以有多个混入 |
| 构造函数 | 允许 | 不允许 |
| 使用场景 | 特化 | 共享行为 |
最棒的是,你可以把两者结合起来:扩展一个类,并混入多种能力,让你的类恰好具备所需的功能。
挑战
简单我们来构建一个工作者系统,演示何时使用继承,何时使用 mixin。你将创建一个表示“是什么”关系的基类,以及表示“能做什么”能力的 mixin,然后将它们组合起来,展示两种方式如何协同工作。
你将把代码分成三个文件:
worker.dart:定义基类,用来确立所有工作者的核心身份:- 创建一个
Worker类,包含String name和String department属性。添加一个接收这两个值的构造函数。添加一个方法introduce(),用于打印[name] works in [department]
- 创建一个
skills.dart:定义表示工作者可能具备的能力(“能做什么”关系)的 mixin:- 创建一个
CanCodemixin,其中的方法writeCode()用于打印Writing code... - 创建一个
CanDesignmixin,其中的方法createDesign()用于打印Creating design... - 创建一个
CanManagemixin,其中的方法leadTeam()用于打印Leading the team...
- 创建一个
main.dart:导入这两个文件,并创建结合继承和 mixin 的专门工作者类型:- 创建一个
Developer类,它继承Worker并使用CanCodemixin - 创建一个
TechLead类,它继承Worker并同时使用CanCode和CanManagemixin - 创建一个名为
'Alice'、所属部门为'Engineering'的Developer - 创建一个名为
'Bob'、所属部门为'Engineering'的TechLead - 对 Alice:先调用
introduce(),再调用writeCode() - 打印一个空行
- 对 Bob:先调用
introduce(),再调用writeCode(),然后调用leadTeam()
- 创建一个
注意,Developer 和 TechLead 都是工作者(继承),但它们能做不同的事情(mixin)。TechLead 通过组合多种能力,无需使用多重继承。
预期输出:
Alice works in Engineering
Writing code...
Bob works in Engineering
Writing code...
Leading the team...亲手试试
import 'worker.dart';
import 'skills.dart';
// TODO: 创建一个继承 Worker 并使用 CanCode 混入的 Developer 类
// TODO: 创建一个继承 Worker 并同时使用 CanCode 和 CanManage 混入的 TechLead 类
void main() {
// TODO: 在 'Engineering' 部门创建一个名为 'Alice' 的 Developer
// TODO: 为 Alice 依次调用 introduce() 和 writeCode()
// TODO: 输出一个空行
// TODO: 在 'Engineering' 部门创建一个名为 'Bob' 的 TechLead
// TODO: 为 Bob 依次调用 introduce()、writeCode() 和 leadTeam()
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器