概念
Mixin是面向对象程序设计语言中的类,用户与Mixin不是“is-a”的关系,而是"-able"关系,这种设计模式体现了依赖反转原则。 Mixin可以在单继承模式下获得多继承的共用性,从而更好地复用代码。
特点
- 不可以声明构造函数,否则在混入多个mixin的时候会产生语法歧义。
- 混用使用
with
关键字,后面可以跟class,abstract class,mixin - mixin用
on
关键字来限定条件
单个mixin
首先看一个简单的例子:
mixin C{
void run(){}
}
class D with C{
}
下面是dart生成的字节码文件:
abstract class C extends core::Object /*isMixinDeclaration*/ {
method run() → void {}
///省略无关信息
}
abstract class _D&Object&C extends core::Object implements main::C /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
method run() → void {}
///省略无关信息
}
class D extends main::_D&Object&C {
}
继承链:C<-_D&Object&C<-D
- 首先Dart会生成一个与mixin C对应的abstract class C'
- 生成一个桥接类
_D&Object&C
继承Object
同时实现C' - D直接继承
_D&Object&C
由此可见mixin创建了一条继承链,并由此来实现代码复用。
多个mixin
多个mixin同时使用会按照出现的前后顺序分别生成桥接类,所以如果多个mixin拥有同一个方法,子类调用方法时以最后一个mixin为准。同样,如果父类和mixin拥有相同方法,mixin会把父类的方法覆盖。
下面是dart生成的字节码文件:
mixin A{
void run(){}
}
mixin B{
void run(){}
}
class C with A,B{
}
--------------------------------字节码--------------------------------------
abstract class A extends core::Object /*isMixinDeclaration*/ {
}
abstract class B extends core::Object /*isMixinDeclaration*/ {
}
abstract class **_C&Object&A** extends core::Object implements main::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
}
abstract class _C&Object&A&B extends main::_C&Object&A implements main::B /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
}
class C extends main::_C&Object&A&B {
}
限定条件
mixin可以限定条件,关键字是on
,后面可以跟class, abstract class或者mixin
- 如果后面跟class或者abstract class,表示只有该class的子类型才能混入该mixin
- 如果后面跟mixin,表示只有该mixin的子类才可以混入。需要注意的是混入顺序:
mixin A{}
mixin B on A{}
///正确写法
class C with A,B{}
///错误写法
class C with B,A{}
下面是实例和字节码:
class Human{
void run(){}
}
mixin ShuffleDance on Human{}
class Girl extends Human with ShuffleDance{}
--------------------------------字节码--------------------------------------
abstract class Human extends core::Object {
}
abstract class ShuffleDance extends main::Human /*isMixinDeclaration*/ {
}
abstract class _Girl&Human&ShuffleDance extends main::Human implements main::ShuffleDance /*isAnonymousMixin,isEliminatedMixin*/ {
}
class Girl extends main::_Girl&Human&ShuffleDance {
}
继承链:Human<-ShuffleDance<-_Girl&Human&ShuffleDance<-Girl
mixin ShuffleDance生成的辅助类是Human的子类,这就是on
关键字的作用
多个限定条件
当存在多个限定条件时会生成多个桥接类,并且按照继承关系从父类到子类的顺序生成。
生成的字节码文件:
class A {
void run() {
print("a");
}
}
mixin B {
void run() {}
}
///混入E前要先implementsA和B
mixin E on A, B {
void run() {
print("e");
}
}
class C extends A with B, E {
void run() {
print("c");
}
}
--------------------------------字节码--------------------------------------
abstract class A extends core::Object {
}
abstract class B extends main::A /*isMixinDeclaration*/ {
}
abstract class _E&A&B extends core::Object implements main::A, main::B /*isAnonymousMixin*/ {
}
abstract class E extends main::_E&A&B /*isMixinDeclaration*/ {
}
abstract class _C&Object&A extends core::Object implements main::A /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
}
abstract class _C&Object&A&B extends main::_C&Object&A implements main::B /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
}
abstract class _C&Object&A&B&E extends main::_C&Object&A&B implements main::E /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
}
class C extends main::_C&Object&A&B&E {
}
Mixin实现链式调用
当一个类混入了一个带限定条件的mixin时,如果两个mixin恰巧又有共同的方法,那么默认会调用最后一个mixin的方法,实例:
mixin A{
void fun(){
print("a");
}
}
mixin B on A{
void fun(){
print("b");
}
}
class C with A,B{
}
C此时调用fun
方法会打印b
现在改造一下mixin B
mixin B on A{
void fun(){
///添加A
super.fun();
print("b");
}
}
C此时调用fun
方法会打印a和b
这种链式调用充分运用了mixin限定条件的依赖关系,可以依次调用接口方法。
具体应用:
- Flutter有一个
BindingBase
类,定义了一个initInstances
接口方法。 WidgetsFlutterBinding, GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding
这些胶水类都依赖于BindingBase
,并重写了initInstances
方法。runApp()
会依次调用这些胶水类的initInstances
方法,初始化应用相关的一系列服务。