跳到主要内容

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 mixinwithon 完全对应的语言语法,常见做法是用函数、接口和类表达式组合行为。Dart 的 Mixin 是类型系统直接支持的类成员复用机制。

常见误区

  • on 是应用约束,不等同于 extends
  • 后应用的 Mixin 可能覆盖前面的同名成员,顺序会影响结果。
  • 普通 mixin 不能直接实例化,也不能声明生成式构造函数。
  • Mixin 适合复用行为,不应承载庞大且彼此无关的状态集合。

小结

  • mixin 声明可复用实例行为,类使用 with 应用它。
  • 抽象成员可以要求应用类提供能力,on 可以限制允许的超类类型。
  • 多个 Mixin 按书写顺序叠加,后者能覆盖前者成员。
  • mixin class 同时支持类和 Mixin 用法,但仍受构造与继承限制。
  • 在继承、Mixin 和组合之间,应根据类型关系、状态和替换需求选择。