本文参考并翻译至:
medium.com/flutter-com…
什么是Mixins
Mixins are a way of reusing a class's code in multiple class hierarchies.
Mixins的字面意思是混入的意思,官方给出的定义是:Mixins是在多继承层次中重用代码的一种方式。
mixin是通过普通的类声明隐式定义的,要使用mixin,需要使用with关键字来实现。
mixin的使用非常简单,通过下面的例子来看下mixin的使用:
class MixinClass {
void method() {
print("mixin method");
}
}
class User with MixinClass {
}
复制代码
在我们的User类中混入MixinClass类,我们就可以使用MixinClass类中的方法。输出User().method()将会打印出mixin method。
Mixins的详细用法
如果只是在我们的类中混入一个类,使用起来非常简单。但是Mixins在特殊情况下的使用,并不那么简单,下面我将就其进行详细说明。
1、混入类中的顺序
首先,我们看一个例子
// 父类
class Super {
void method() {
print("Super class method");
}
}
// 混入类1
class M1 {
void method() {
print("M1 class method");
}
}
// 混入类2
class M2 {
void method() {
print("M2 class method");
}
}
// 子类1实现
class Child1 extends Super with M1, M2 {}
// 子类2实现
class Child2 extends Super with M2, M1 {}
void main() {
Child1().method();
Child2().method();
}
复制代码
在上面的这个例子中,Child1和Child2都是混入了M1和M2类,但是M1和M2的顺序是不一样的,运行他们的输出结果:
M2 class method
M1 class method
复制代码
我们可以看出来,mixins声明的顺序影响了方法的输出结果,同时后面mixins的类方法会覆盖前面mixins类的方法,针对这种情况,Lasse R.H.Nielsen大神给出了解释:
Mixins in Dart work by creating a new class that layers the implementation of the mixin on top of a superclass to create a new class — it is not “on the side” but “on top” of the superclass, so there is no ambiguity in how to resolve lookups.
复制代码
翻译成中文为:在Dart语言中,Mixins通过创建一个新类来工作,这个新类将mixin的实现层放在了父类之上。这里重点强调了这个新类是在父类之上,并不是在旁边。因此,在解析查找方面没有任何歧义。
结合Lasse R.H.Nielsen大神的解释,我们重新看下这段代码:
class Child1 extends Super with M1, M2 {}
class Child2 extends Super with M2, M1 {}
复制代码
上面这段代码可以等价于:
// Child1
class Mixin1_1 => Super with M1;
class Mixin1_2 => Mixin1_1 with M2;
class Child1 extends Mixin1_2;
// Child2
class Mixin2_1 => Super with M2;
class Mixin2_2 => Mixin2_1 with M1;
class Child2 extends Mixin2_2;
复制代码
通过这样写,我们基本上已经找到了上面输出结果的原因了。这些新类创建在父类和子类中间,是一个mix_in类,并没有表现出多重继承。
Lasse R.H.Nielsen大神又给出了这么一种解释:
Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear.
复制代码
这里翻译成中文为:Mixins并不是传统意义上实现多重继承的一种方式。Mixin是实现抽象和重用一系列方法和状态的一种方式。Mixins和扩展类中的重用是相似的,Mixins也和单继承兼容,它是一种线性关系。
注意:mixins的顺序代表着从父类到子类继承的顺序。
通过上面的解释,我们继续刚才的例子,如果我们在Child1或者Child2中实现了method方法
class Child1 extends Super with M1, M2 {
void method() => print("Child1 class method");
}
class Child2 extends Super with M2, M1 {
void method() => print("Child2 class method");
}
复制代码
运行后的输入结果同样也是显而易见的:
Child1 class method
Child2 class method
复制代码
最后,我们用继承关系图(并不是真正的继承关系,想象成继承关系)更加直观的表示下这个例子:
2、混入类中添加限定
首先,我们来看一个例子
abstract class Super {
void method() => print("Super class method");
}
mixin MixinClass on Super {
void method() => print("Mixin class method");
}
class Child extends Super with MixinClass {}
复制代码
在这个例子中我们通过mixin关键字声明了混入类Mixin,通过关键字on添加了父类限制,这意味着如果一个类想要引入这个混入类,这个类必须继承或者实现这个父类。
在这个例子中如果写成这样:
class Child with MixinClass {}
复制代码
则会报编译错误:
'MixinClass' can't be mixed onto 'Object' because 'Object' doesn't implement 'MixinClass'.
Try extending the class 'MixinClass'
复制代码
现在我们继续修改下这个例子,给混入类添加super方法
mixin MixinClass on Super {
void method() {
super.method();
print("Mixin class method");
}
}
复制代码
运行Child().method()后输出为:
Super class method
Mixin class method
复制代码
回过头去看下1、混入类中的顺序中的继承关系图,那么得出这个结果就是显而易见的。
WidgetsFlutterBinding中mixins的应用
在前面我们学习到了Mixins使用,Flutter中关于Mixins的最重要的使用就是WidgetsFlutterBinding类,WidgetsFlutterBinding在Flutter进行初始化的时候创建,依次进行了手势、调度、绘制等的绑定。我们这次的目的就是说明下各个Binding的执行顺序。
WidgetsFlutterBinding具体实现如下:
// 1、BindingBase
abstract class BindingBase {
BindingBase() {
initInstances();
}
}
// 2、GestureBinding
mixin GestureBinding on BindingBase {
void initInstances() {
super.initInstances();
}
}
// 3、WidgetsFlutterBinding
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
复制代码
针对以上代码,我们分析过程如下:
- 定义了一个抽象类BindingBase,其构造函数执行了初始化initInstances()。
- 定义了一个混入类GestureBinding(ServuceBinding等类实现原理相同),添加了父类限制BindingBase,引入类中必须实现继承/实现BindingBase类。
- 定义了一个实现类WidgetsFlutterBinding,继承BindingBase,混入了GestureBinding、ServiceBinding等类。
- Flutter初始化时执行WidgetsFlutterBinding.ensureInitialized()单例方法,创建WidgetsFlutterBinding对象,执行其构造函数,这里执行的是BindingBase构造函数。
- BindingBase构造函数执行initInstance(),通过前面继承关系图可知,继承关系如下:WidgetsFlutterBinding->WidgetsBinding->RendererBinding->…->GestureBinding->BindingBase。执行的是WidgetsBinding的initInstance()方法。
- WidgetsBinding中initInstance()方法调用了super.initInstance()方法,最终initInstance()执行顺序为GestureBinding->ServiceBinding->…->WidgetsBinding。
总结
通过以上我们了解到了Mixins的用法,以及其在WidgetsFlutterBinding类中的使用。通过阅读本篇文章希望能对大家了解Mixins有所帮助。新人第一次尝试写文章,其中不当的地方也欢迎大家指正。