Dart 只有单继承,但很多业务能力又确实需要“按模块拼装”,比如日志、校验、权限、状态通知这类横切逻辑。Mixin 正是 Dart 为这类复用场景提供的标准机制:通过 with 把已经封装好的方法和属性混入宿主类,在不引入传统多继承复杂度的前提下完成能力组合。
这篇文章按“先理解概念,再看规则,再看边界”的顺序展开,重点说明 Dart Mixin 能做什么、多个 Mixin 一起使用时谁覆盖谁、on 如何限制宿主类型,以及宿主类怎样重写混入方法。读完后,你基本可以判断一个公共能力该写成继承、接口,还是更适合写成 Mixin。
什么是 Dart Mixin
Mixin 可以理解为“专门用于被混入的功能模块”。它本身不能被实例化,但可以包含方法和属性,供其他类通过 with 直接复用。
- Mixin 的目标是复用代码,而不是单独创建对象。
- 它可以包含方法和属性。
- 它也可以定义抽象方法,用来约束宿主类必须补齐实现。
- 命名上通常建议以
Mixin结尾,方便阅读和维护。 - 设计时应保持单一职责,避免一个 Mixin 塞入过多无关能力。
最基本的写法就是用 mixin 声明,再通过 with 混入到类中:
//通过 mixin 关键字声明
mixin FlyMixin {
String info = "来自 FlyMixin";
void fly() => print('Flying');
}
class BirdClass with FlyMixin {}
void main() {
//
var birdClass = BirdClass();
print('birdClass info=${birdClass.info}');
birdClass.fly();
//--------- 打印 -------------
//birdClass info=来自 FlyMixin
//Flying
}
从这个例子就能看出,BirdClass 虽然没有自己声明 info 和 fly(),但在混入 FlyMixin 后就直接拥有了这些成员。
多个 Mixin 怎么同时使用
当一个类需要组合多种能力时,可以在 with 后面连续写多个 Mixin,并用逗号分隔:

- 写法是
with AMixin, BMixin。 - 如果多个 Mixin 或基类里存在同名成员,后混入的 Mixin 优先级更高。
- 如果类本身有父类,那么普通类要写在前面,Mixin 写在
with后面。
class BaseClass {
void test() => print("test BaseClass");
}
mixin AMixin {
void test() => print("test AMixin");
}
mixin BMixin {
void test() => print("test BMixin");
}
class CClass with AMixin, BMixin {}
class DClass with BMixin, AMixin {}
//类(非 Mixin)需要位于 Mixin 之前
class EClass extends BaseClass with AMixin, BMixin {}
void main() {
var cClass = CClass();
cClass.test();
//
var dClass = DClass();
dClass.test();
//
var eClass = EClass();
eClass.test();
//--------- 打印 -------------
//test BMixin
//test AMixin
//test BMixin
}
这里最关键的是“顺序决定结果”。
同名成员按什么顺序生效
从输出可以直接看出:
CClass with AMixin, BMixin最终调用的是BMixin.test()DClass with BMixin, AMixin最终调用的是AMixin.test()EClass extends BaseClass with AMixin, BMixin即使父类已有同名方法,最终仍然是最后混入的BMixin生效
也就是说,在 Dart 的 Mixin 线性化顺序里,越靠后的 Mixin,优先级越高。方法如此,属性解析规则也是一致的。
如何用 on 限制 Mixin 的适用范围
有些 Mixin 并不是谁都能混入。比如一个飞行能力可能依赖宿主类已经具备某些字段或基础行为,这时就可以用 on 指定它只能作用在某类体系之上。

on 的意义是限制宿主类型,确保类型安全。宿主类必须先继承指定基类,才能混入该 Mixin。
mixin AMixin { }
//相当于
mixin AMixin on Object { }
class AnimalClass {
String info = "来自 AnimalClass";
}
mixin FlyMixin on AnimalClass {
void fly() => print('Flying');
}
class BirdClass extends AnimalClass with FlyMixin {}
class CarClass with FlyMixin {} //编译报错:'FlyMixin' can't be mixed onto 'Object' because 'Object' doesn't implement 'AnimalClass'.
为什么 on 很重要
- 它能明确表达某个 Mixin 的依赖前提。
- 它避免把能力混入到不具备基础结构的类上。
- 它让编译器在编译阶段就拦下错误,而不是把问题留到运行时。
像上面的 FlyMixin on AnimalClass,就明确要求宿主类至少是 AnimalClass 体系的一部分,因此 BirdClass 合法,CarClass 则会直接编译失败。
宿主类怎样重写 Mixin 方法
Mixin 混入后,宿主类仍然可以通过 @override 重写其中的方法。如果希望保留原始逻辑,还可以用 super 调回 Mixin 里的实现。

mixin AMixin {
void test() {
print("test AMixin");
}
}
class BClass with AMixin {
@override
void test() {
super.test(); //调用 AMixin 的 test 方法
print("test BClass");
}
}
void main() {
var bClass = BClass();
bClass.test();
//--------- 打印 -------------
//test AMixin
//test BClass
}
这类写法适合“在公共能力基础上追加业务逻辑”的场景。也就是先复用 Mixin 的通用实现,再由宿主类补充自己特有的处理流程。
mixin class 是什么
Dart 还提供了 mixin class 这种形式,用来同时声明“它既是类,也是可混入能力”。这种类型既能像普通类一样被继承或实例化使用,也能像 Mixin 一样参与 with 混入。
原文示例里提到,这类写法常见于类似 ChangeNotifier 的能力设计。需要注意的是,适用于类或混入的限制,同样适用于 mixin class;比如它不能使用 on。
mixin class A {}
class B with A {}
class C extends A {}
这意味着:
B把A当作混入来用C则把A当作普通类来继承
当你希望一份能力同时支持“直接当类使用”和“作为能力模块被混入”时,mixin class 会更灵活。
什么时候该用 Dart Mixin
如果你的目标是复用一段可横向组合的通用能力,而不是建立严格的父子层级关系,那么 Mixin 往往比继承更合适。
- Mixin 只能通过
with把功能添加到宿主类中。 - 它能绕开传统多继承的复杂性,同时保持模块化和可维护性。
- 多个 Mixin 可以灵活组合,适合封装日志、网络请求、数据校验、权限校验等通用逻辑。
- 可以通过
on限制使用范围,保证类型安全。 - 如果出现同名成员冲突,最后混入的 Mixin 优先级最高。
实际开发里,一个经验判断是:如果你复用的是“能力”,优先考虑 Mixin;如果你描述的是“是什么”,再考虑继承;如果你只想约束行为而不提供实现,则更偏向接口或抽象类。













