Mixin

Mixin 是一种代码复用技术,旨在为类添加新成员。简单地说,mixin 是可复用的代码片段。 本章节将介绍mixin基础mixin类,以及解决mixin成员依赖问题的3种策略。

Mixin 基础

使用 mixin 关键字声明 mixin。

// ex531.dart
mixin Starter {
  var started = false;

  void start() => started = true;
}

在声明类时,使用关键字 with 为其添加 mixin。

// ex532.dart
import './ex531.dart';

class Game with Starter {}

class Engine with Starter {}

void main() {
  var g = Game();
  print(g.started); // Output: false
  g.start();
  print(g.started); // Output: true
}

with 子句可与 extends 子句连用,且可以为一个类添加多个mixin。

// ex533.dart
import './ex531.dart';

mixin Leveler {
  int level = 0;
}

class Fun {}

class Game extends Fun with Starter, Leveler {}

void main() {
  var g = Game();
  g.level = 3;
  g.start();
  print('${g.level} ${g.started}'); // Output: 3 true
}

mixin 不能有 extendswith 子句,也不能声明构造函数。

Mixin 类

使用 mixin class 声明一个 mixin 类。mixin类可同时作为类和mixin使用,但也有更多的限制,实际中它的应用不多。

// ex534.dart
mixin class Player {
  late String playerName;
}

mixin 类不能有 extendswithon 子句,也不能定义生成式构造函数。

Mixin 成员依赖

有时候一个mixin需要访问一些不由它自己定义的成员(字段/方法)。换句话说,使用该mixin的类需要或显示或隐式地实现某个接口,这个接口正好包含了mixin所需的成员。下面讨论解决成员依赖的3种策略。

策略1:在mixin中定义抽象成员

// ex535.dart
mixin Adder {
  set count(int value); // 1
  int get count; // 1a

  void add(int amount) => count += amount; // 2
}

// 3
class AddCounter with Adder {
  @override
  int count = 0;
}

void main() {
  var c = AddCounter();
  c.add(2);
  assert(c.count == 2);
}
  1. Adder mixin 为属性count定义了抽象的getter和setter;
  2. Adder.add(int) 方法调用了count的getter和setter;
  3. AddCounter 类使用了 Adder mixin,且实现了count的getter和setter两个抽象方法。

策略2:让mixin实现一个接口

让 mixin 实现一个接口,使用该 mixin 的类也自然地实现了该接口。对上述 Adder mixin 进行重构,对它的两个抽象方法(即count的getter和setter),抽取至一个接口中,形成如下版本。

// ex536.dart
abstract interface class Countable {
  set count(int value); // 1
  int get count; // 1a
}

mixin Adder implements Countable {
  void add(int amount) => count += amount; // 2
}

// 3
class AddCounter with Adder {
  @override
  int count = 0;
}
  1. Countable 接口定义了属性count的getter和setter;
  2. Adder mixin 实现了 Countable
  3. AddCounter 类使用了 Adder mixin,自然地实现了Countable接口。

可以向下面这样声明AddCounter类:

class AddCounter with Adder implements Countable {
 // ... (omitted for brevity)
}

策略3:使用 on 子句定义超类

在声明mixin是使用on子句,用以限制mixin应用于哪些类。例如:

mixin Adder on Counter {
}

只有Counter的子孙类才可以使用 Adder mixin。同时,Adder 也可以访问 Counter 中的成员(字段/方法)。让Counter 隐式地实现 Countable 接口,形成如下新版本。

// ex537.dart
class Counter {
  int count = 0; // 1
}

mixin Adder on Counter {
  void add(int amount) => count += amount; // 2
}

class AddCounter extends Counter with Adder {} // 3

参考资料