Flutter学习系列(一)—mixins

本文参考并翻译至:
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
复制代码

最后,我们用继承关系图(并不是真正的继承关系,想象成继承关系)更加直观的表示下这个例子:
image.png

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;
  }
}
复制代码

针对以上代码,我们分析过程如下:

  1. 定义了一个抽象类BindingBase,其构造函数执行了初始化initInstances()。
  2. 定义了一个混入类GestureBinding(ServuceBinding等类实现原理相同),添加了父类限制BindingBase,引入类中必须实现继承/实现BindingBase类。
  3. 定义了一个实现类WidgetsFlutterBinding,继承BindingBase,混入了GestureBinding、ServiceBinding等类。
  4. Flutter初始化时执行WidgetsFlutterBinding.ensureInitialized()单例方法,创建WidgetsFlutterBinding对象,执行其构造函数,这里执行的是BindingBase构造函数。
  5. BindingBase构造函数执行initInstance(),通过前面继承关系图可知,继承关系如下:WidgetsFlutterBinding->WidgetsBinding->RendererBinding->…->GestureBinding->BindingBase。执行的是WidgetsBinding的initInstance()方法。
  6. WidgetsBinding中initInstance()方法调用了super.initInstance()方法,最终initInstance()执行顺序为GestureBinding->ServiceBinding->…->WidgetsBinding。

总结

通过以上我们了解到了Mixins的用法,以及其在WidgetsFlutterBinding类中的使用。通过阅读本篇文章希望能对大家了解Mixins有所帮助。新人第一次尝试写文章,其中不当的地方也欢迎大家指正。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享