组合与继承
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 82 课,共 110 课。
你已经学过,继承会建立一种“is-a”关系,也就是 Dog 是一种 Animal。还有一种强大的方法:组合,它会建立一种“has-a”关系。类不继承行为,而是包含其他类的实例,并把工作委托给它们。
考虑一个 Car 类。使用继承时,你可能会尝试扩展一个 Engine 类,但汽车不是发动机,而是拥有发动机:
class Engine {
void start() => print('Engine started');
}
class Car {
final Engine _engine = Engine(); // 组合:Car 拥有一个 Engine
void start() {
_engine.start(); // 交给引擎处理
print('Car is ready to drive');
}
}
void main() {
var car = Car();
car.start();
}组合的主要优势是灵活性。使用继承时,你只能依赖单个父类。使用组合时,你可以组合多个组件,甚至可以在运行时替换它们:
class ElectricEngine {
void start() => print('Electric motor humming');
}
class HybridCar {
Engine? _gasEngine;
ElectricEngine? _electricEngine;
HybridCar({bool useElectric = false}) {
if (useElectric) {
_electricEngine = ElectricEngine();
} else {
_gasEngine = Engine();
}
}
}一个常见的指导原则是“优先使用组合,而不是继承”。当确实存在“是一个”的关系,并且你需要多态时,使用继承。当你想复用行为而不产生紧密耦合,或者对象需要具备来自多个来源的能力时,使用组合。
挑战
简单让我们用组合来构建一个计算机系统!你不用让计算机继承它的各个部件,而是创建独立的组件类,再把它们组合起来,因为计算机拥有 CPU 和内存,而不是 CPU 或内存。
你要把代码分成三个文件:
components.dart:创建两个表示计算机部件的组件类:- 创建一个
CPU类,包含String brand和double speedGHz。添加一个process()方法,返回一个字符串:[brand] processing at [speedGHz]GHz - 创建一个
Memory类,包含一个int sizeGB。添加一个load()方法,返回一个字符串:Loading [sizeGB]GB of data
- 创建一个
computer.dart:创建一个使用组合来整合这些组件的Computer类。你的计算机应该:- 有一个
String name字段 - 包含一个
CPU实例和一个Memory实例(组合,也就是计算机拥有这些部件) - 通过构造函数接收创建这两个组件所需的所有值,并在内部创建它们
- 有一个
boot()方法,将工作委托给这两个组件,并打印三行内容:先打印计算机名称,后接starting...,然后打印 CPU 的 process 方法的结果,最后打印 Memory 的 load 方法的结果 - 有一个
specs()方法,返回描述系统的字符串:[name]: [brand] [speedGHz]GHz, [sizeGB]GB RAM
- 有一个
main.dart:导入你的文件,并演示组合的实际效果:- 创建一个名为
Workstation的Computer,配备一个运行频率为3.5GHz 的IntelCPU 和16GB 内存 - 调用
boot()方法 - 打印
specs()的结果
- 创建一个名为
注意,Computer 类没有继承 CPU 或 Memory,而是包含它们,并将工作委托给它们。这就是组合所建立的“拥有”关系!
预期输出:
Workstation starting...
Intel processing at 3.5GHz
Loading 16GB of data
Workstation: Intel 3.5GHz, 16GB RAM亲手试试
import 'computer.dart';
void main() {
// TODO:创建一个名为 "Workstation" 的 Computer 对象,配置如下:
// Intel CPU,运行频率为 3.5 GHz
// 16 GB 内存
// TODO:调用 boot() 方法
// TODO:打印 specs() 的结果
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器