Menu
CoddyTech

组合与继承

本课属于 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();
    }
  }
}

一个常见的指导原则是“优先使用组合,而不是继承”。当确实存在“是一个”的关系,并且你需要多态时,使用继承。当你想复用行为而不产生紧密耦合,或者对象需要具备来自多个来源的能力时,使用组合。

challenge icon

挑战

简单

让我们用组合来构建一个计算机系统!你不用让计算机继承它的各个部件,而是创建独立的组件类,再把它们组合起来,因为计算机拥有 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.5 GHz 的 Intel CPU 和 16 GB 内存
    • 调用 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() 的结果
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器