Skip to content

Mixins(混入)

Mixins 是一种可在多个类层次结构中复用代码的方式,旨在批量提供成员实现。

使用 Mixin

通过 with 关键字后跟一个或多个 mixin 名称来使用 mixin。以下示例展示了两个使用(或继承)mixin 的类:

dart
class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

content_copy

定义 Mixin

使用 mixin 声明来定义 mixin。极少数情况下,如果需要同时定义 mixin 和类,可以使用 mixin class 声明。

注意

  • Mixin 和 mixin 类不能有 extends 子句。
  • 不能声明任何生成式构造函数(generative constructors)。

示例:

dart
mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

指定 Mixin 可调用的自身成员

有时 mixin 依赖调用某个方法或访问某些字段,但无法自行定义这些成员(因为 mixin 不能通过构造函数参数初始化自己的字段)。以下是几种确保 mixin 的子类定义其依赖成员的策略:

1. 在 Mixin 中定义抽象成员

在 mixin 中声明抽象方法,强制使用该 mixin 的类型必须定义其依赖的抽象方法。

dart
mixin Musician {
  void playInstrument(String instrumentName); // 抽象方法

  void playPiano() {
    playInstrument('Piano');
  }

  void playFlute() {
    playInstrument('Flute');
  }
}

class Virtuoso with Musician { 
  @override
  void playInstrument(String instrumentName) { // 子类必须实现
    print('Plays the $instrumentName beautifully');
  }  
}

2. 访问 Mixin 子类的状态

通过声明抽象成员,还可以在 mixin 中访问子类的状态,即调用 mixin 中定义为抽象的 getter:

dart
/// 可应用于任何具有 [name] 属性的类型,并基于该属性提供 [hashCode]`==` 运算符的实现。
mixin NameIdentity {
  String get name;

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator ==(other) => other is NameIdentity && name == other.name;
}

class Person with NameIdentity {
  final String name;

  Person(this.name);
}

3. 实现接口

类似于声明 mixin 为抽象类,在 mixin 上添加 implements 子句(但不实际实现接口)也能确保 mixin 的成员依赖被定义。

dart
abstract interface class Tuner {
  void tuneInstrument();
}

mixin Guitarist implements Tuner {
  void playSong() {
    tuneInstrument();
    print('Strums guitar majestically.');
  }
}

class PunkRocker with Guitarist {
  @override
  void tuneInstrument() {
    print("Don't bother, being out of tune is punk rock.");
  }
}

4. 使用 on 子句声明父类

on 子句用于定义 super 调用解析的目标类型。因此,只有当需要在 mixin 中使用 super 调用时才应使用它。

on 子句强制任何使用该 mixin 的类也必须是 on 子句中类型的子类。如果 mixin 依赖父类的成员,这能确保这些成员在 mixin 使用时可用。

示例:

dart
class Musician {
  musicianMethod() {
    print('Playing music!');
  }
}

mixin MusicalPerformer on Musician {
  performerMethod() {
    print('Performing music!');
    super.musicianMethod();
  }
}

class SingerDancer extends Musician with MusicalPerformer { }

main() {
  SingerDancer().performerMethod();
}

在此示例中,只有继承或实现 Musician 类的类才能使用 MusicalPerformer mixin。由于 SingerDancer 继承自 Musician,因此它可以混入 MusicalPerformer


class、mixin 还是 mixin class?

版本说明

mixin class 声明需要 Dart 语言版本至少为 3.0。

  • mixin 声明定义了一个 mixin。
  • class 声明定义了一个类。
  • mixin class 声明定义了一个既可作为普通类又可作为 mixin 使用的类(同名同类型)。

示例:

dart
mixin class Musician {
  // ...
}

class Novice with Musician { // 将 Musician 用作 mixin
  // ...
}

class Novice extends Musician { // 将 Musician 用作类
  // ...
}

限制

  • 适用于类或 mixin 的限制同样适用于 mixin 类:
    • Mixin 不能有 extendswith 子句,因此 mixin 类也不能有。
    • 类不能有 on 子句,因此 mixin 类也不能有。