现在位置: 首页 > Dart 教程 > 正文

Dart 接口与 Mixin

虽然 Dart 只支持单继承,但通过接口和 Mixin 可以灵活地实现多重代码复用。

本章介绍如何使用 implements 实现接口、mixin 的代码复用以及 with 关键字。


implements 实现接口

在 Dart 中,每个类都隐式定义了一个接口。

使用 implements 关键字可以让一个类实现另一个类的接口,且可以实现多个。

实例

// 定义一个"可打印"的接口
class Printable {
  // 接口中的方法没有默认实现
  // 实现者必须重写所有成员
  void printContent() {
    // 这个方法体在 implements 时会被忽略
  }
}

// 定义一个"可保存"的接口
class Savable {
  void save() {}
}

// 使用 implements 实现多个接口
class Document implements Printable, Savable {
  String title;
  String content;

  Document(this.title, this.content);

  // 必须实现 Printable 接口要求的所有方法
  @override
  void printContent() {
    print('--- 文档: $title ---');
    print(content);
    print('--- RUNOOB 打印结束 ---');
  }

  // 必须实现 Savable 接口要求的所有方法
  @override
  void save() {
    print('文档 "$title" 已保存到磁盘');
  }
}

void main() {
  var doc = Document('Dart 教程', '这是一份 Dart 入门指南');

  // 多态:Document 既是 Printable 也是 Savable
  Printable printable = doc;
  printable.printContent();

  Savable savable = doc;
  savable.save();
}
--- 文档: Dart 教程 ---
这是一份 Dart 入门指南
--- RUNOOB 打印结束 ---
文档 "Dart 教程" 已保存到磁盘

implements 和 extends 的关键区别:extends 继承父类的所有实现(方法体),而 implements 只继承接口签名,你必须重新实现所有方法。此外,extends 只能继承一个类,implements 可以实现多个接口。

extends vs implements 对比

特性extendsimplements
数量限制只能继承一个可以实现多个
方法实现继承父类的实现必须自己实现所有方法
构造函数可以调用 super()不继承构造函数
使用场景"是一个"的关系"能做什么"的契约

多接口实现

Dart 可以实现多个接口,这是突破单继承限制的主要方式。

实例

// 定义多个行为接口
class Flyable {
  void fly() {}
}

class Swimmable {
  void swim() {}
}

class Walkable {
  void walk() {}
}

// 一只鸭子可以飞、游、走
class Duck implements Flyable, Swimmable, Walkable {
  String name;

  Duck(this.name);

  @override
  void fly() {
    print('$name 在天空中飞翔');
  }

  @override
  void swim() {
    print('$name 在水面上游泳');
  }

  @override
  void walk() {
    print('$name 在陆地上摇摇晃晃地走');
  }
}

// 一条鱼只能游
class Fish implements Swimmable {
  @override
  void swim() {
    print('鱼儿在水中游动');
  }
}

void main() {
  var duck = Duck('RUNOOB 鸭');

  // 鸭子可以扮演多种角色
  (duck as Flyable).fly();
  (duck as Swimmable).swim();
  (duck as Walkable).walk();

  // 类型检查
  print('鸭子能飞吗? ${duck is Flyable}');
  print('鸭子能游吗? ${duck is Swimmable}');

  var fish = Fish();
  print('鱼能飞吗? ${fish is Flyable}');
}
RUNOOB 鸭 在天空中飞翔
RUNOOB 鸭 在水面上游泳
RUNOOB 鸭 在陆地上摇摇晃晃地走
鸭子能飞吗? true
鸭子能游吗? true
鱼能飞吗? false

Mixin 代码复用

Mixin 是一种在多个类之间复用代码的机制,它解决了"多个类需要共享相同方法但又不适合继承"的问题。

使用 mixin 关键字定义一个 Mixin,使用 with 关键字将其混入到类中。

实例

// 使用 mixin 关键字定义
mixin Logger {
  // Mixin 中的方法可以被多个类复用
  void log(String message) {
    print('[${DateTime.now()}] $message');
  }

  void logError(String message) {
    print('[ERROR ${DateTime.now()}] $message');
  }
}

mixin TimestampFormatter {
  String formatTimestamp(DateTime dt) {
    return '${dt.year}-${dt.month.toString().padLeft(2, '0')}'
        '-${dt.day.toString().padLeft(2, '0')}';
  }
}

// 使用 with 关键字混入 Mixin
class UserService with Logger, TimestampFormatter {
  void createUser(String name) {
    log('创建用户: $name');
    var now = DateTime.now();
    print('创建时间: ${formatTimestamp(now)}');
  }
}

class OrderService with Logger {
  void createOrder(String orderId) {
    log('创建订单: $orderId');
  }

  void cancelOrder(String orderId) {
    logError('取消订单失败: $orderId');
  }
}

void main() {
  var userService = UserService();
  userService.createUser('runoob');

  var orderService = OrderService();
  orderService.createOrder('ORD-001');
  orderService.cancelOrder('ORD-001');
}
[2026-06-12 10:30:00.000] 创建用户: runoob
创建时间: 2026-06-12
[2026-06-12 10:30:00.001] 创建订单: ORD-001
[ERROR 2026-06-12 10:30:00.001] 取消订单失败: ORD-001

UserService 和 OrderService 来自不同的业务领域,不适合用继承来共享 Logger。

通过 Mixin,它们都能获得日志功能,而且互不影响。

Mixin 不能有构造函数,也不能被实例化。它的定位很纯粹:提供可复用的方法,不涉及状态初始化。

Mixin 的限制条件

Mixin 可以使用 on 关键字限制它只能被特定类型的类使用。

实例

// 基础类
class Animal {
  String name;
  Animal(this.name);
}

// 这个 Mixin 只能混入到 Animal 及其子类中
mixin FlyableMixin on Animal {
  void fly() {
    print('$name 飞起来了!');
  }
}

// Bird 是 Animal,可以用 FlyableMixin
class Bird extends Animal with FlyableMixin {
  Bird(String name) : super(name);
}

// 下面这行会报错:Car 不是 Animal,不能用 FlyableMixin
// class Car with FlyableMixin {}  // 错误!

void main() {
  var bird = Bird('RUNOOB 小鸟');
  bird.fly();

  // FlyableMixin 中的方法可以访问 Animal 的属性 name
  print('小鸟的名字: ${bird.name}');
}
RUNOOB 小鸟 飞起来了!
小鸟的名字: RUNOOB 小鸟

class、Mixin、extends、implements 的完整组合

Dart 中一个类可以同时使用 extends、with 和 implements:

实例

mixin Jumpable {
  void jump() => print('跳起来!');
}

mixin Runnable {
  void run() => print('跑步前进!');
}

class Animal {
  void breathe() => print('呼吸...');
}

// 继承 Animal,混入 Jumpable 和 Runnable,实现 Comparable
class Athlete extends Animal
    with Jumpable, Runnable
    implements Comparable<Athlete> {
  String name;
  int score;

  Athlete(this.name, this.score);

  @override
  int compareTo(Athlete other) => score.compareTo(other.score);

  void showSkills() {
    breathe();
    run();
    jump();
  }
}

void main() {
  var a1 = Athlete('RUNOOB 选手A', 95);
  var a2 = Athlete('选手B', 88);

  a1.showSkills();
  print('${a1.name} vs ${a2.name}: ${a1.compareTo(a2) > 0 ? "A 胜" : "B 胜"}');
}
呼吸...
跑步前进!
跳起来!
RUNOOB 选手A vs 选手B: A 胜

完整声明顺序:class 子类 extends 父类 with Mixin1, Mixin2 implements 接口1, 接口2