Mixins(混入)
Mixin 用于把一组可复用的实例行为加入多个类,而不要求这些类共享同一个直接超类。类通过 with 应用 Mixin;这适合横向复用能力,但不应代替清晰的对象组合和领域建模。
声明并应用 Mixin
使用 mixin 声明 Mixin:
mixin Loggable {
void log(String message) {
print('[${runtimeType}] $message');
}
}
class FileService with Loggable {
void save() {
log('saved');
}
}
void main() {
FileService().save(); // [FileService] saved
}
FileService 获得了 log() 的实现。Mixin 中的 this 指向应用它的类所创建的实例。
依赖应用类提供成员
Mixin 可以声明抽象成员,要求应用它的类提供实现:
mixin NamedLogger {
String get name;
void logName() {
print('Name: $name');
}
}
class User with NamedLogger {
final String name;
User(this.name);
}
NamedLogger 可以在具体方法中使用 name,但任何应用它的具体类都必须满足这个成员契约。
使用 on 限制超类
当 Mixin 需要访问某个超类接口或调用 super 时,可以使用 on 约束可应用范围:
class Performer {
void perform() {
print('performing');
}
}
mixin Encore on Performer {
void perform() {
super.perform();
print('encore');
}
}
class Singer extends Performer with Encore {}
void main() {
Singer().perform();
// performing
// encore
}
on Performer 表示只有 Performer 的子类型才能应用 Encore。它不是继承声明:Encore 本身不会因此成为 Performer 的子类。
多个 Mixin 的顺序
一个类可以应用多个 Mixin,后写的 Mixin 会覆盖前面提供的同名成员:
mixin First {
String label() => 'first';
}
mixin Second {
String label() => 'second';
}
class Example with First, Second {}
void main() {
print(Example().label()); // second
}
可以把 class Example with First, Second 理解为先加入 First,再在其结果上加入 Second。存在同名成员时,应谨慎安排顺序,并在最终类中显式重写以表达意图。
mixin class
mixin class 同时允许声明被当作普通类实例化或继承,也允许通过 with 应用:
mixin class CounterBehavior {
int count = 0;
void increment() {
count++;
}
}
class Controller with CounterBehavior {}
普通 mixin 不能被实例化。mixin class 也有约束:不能声明生成式构造函数,也不能使用 extends 子句。需要复杂构造状态时,组合对象通常更清晰。
字段与状态
Mixin 可以声明实例字段。每个应用该 Mixin 的对象都会拥有对应状态:
mixin Activatable {
bool isActive = false;
void activate() {
isActive = true;
}
}
class Job with Activatable {}
字段名可能与应用类或其他 Mixin 冲突。可复用 Mixin 应尽量保持职责单一,避免引入大量隐式状态。
Mixin、继承与组合
三种复用方式解决的问题不同:
| 方式 | 适合场景 | 主要特征 |
|---|---|---|
extends | 明确的“是一个”类型关系 | 单继承,可复用超类实现 |
with | 多个无关类型共享一组行为 | 可应用多个,成员按顺序叠加 |
| 组合 | 对象把工作委托给另一个对象 | 依赖显式,运行时可替换 |
如果行为需要独立生命周期、构造参数或运行时替换,优先考虑组合;如果只是为多个类加入紧凑且稳定的实例能力,Mixin 更合适。
TypeScript 对比:TypeScript 没有与 Dart
mixin、with和on完全对应的语言语法,常见做法是用函数、接口和类表达式组合行为。Dart 的 Mixin 是类型系统直接支持的类成员复用机制。
常见误区
on是应用约束,不等同于extends。- 后应用的 Mixin 可能覆盖前面的同名成员,顺序会影响结果。
- 普通
mixin不能直接实例化,也不能声明生成式构造函数。 - Mixin 适合复用行为,不应承载庞大且彼此无关的状态集合。
小结
mixin声明可复用实例行为,类使用with应用它。- 抽象成员可以要求应用类提供能力,
on可以限制允许的超类类型。 - 多个 Mixin 按书写顺序叠加,后者能覆盖前者成员。
mixin class同时支持类和 Mixin 用法,但仍受构造与继承限制。- 在继承、Mixin 和组合之间,应根据类型关系、状态和替换需求选择。