Featured image of post Flutter/Dart第05天:Dart特殊特性Mixin详解

Flutter/Dart第05天:Dart特殊特性Mixin详解

摘要:在Java语言中,子类只能继承extends单个父类,实现implements多个接口(即单继承和多实现)。在Dart语言中,所有类型均是Object子类,它们也是单继承和多实现,但Dart中有个Mixin的高级特性,它可以做到更多的代码复用(单继承、多实现、多Mixin代码复用)……

Dart官网文档:https://dart.dev/language/mixins

重要说明:本博客基于Dart官网文档,但并不是简单的对官网进行翻译,在覆盖核心功能情况下,我会根据个人研发经验,加入自己的一些扩展问题和场景验证。

Mixin目的和使用方法(with)

官网文档:Mixins are a way of defining code that can be reused in multiple class hierarchies. They are intended to provide member implementations en masse.

大概意思:Mixin是一种定义可在多个类层次结构中复用代码的方法。Mixin的目标是为这些类提供一批成员实现(类属性+类方法)。

总结起来:使用Mixin可以让代码被其他类所使用(包括属性和方法)。

使用方法:通过mixin关键字定义一个Mixin类;通过with关键字,一个类可以同时复用多个mixin成员实现。

代码样例:如下代码,ClassA同时拥有了MixinOne+MixinTwo+MixinThree这3个Mixin的所有成员属性和类方法(感觉有的像多继承?)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
mixin MixinOne {
  ......
}

mixin MixinTwo {
  ......
}

mixin MixinThree {
  ......
}

class ClassA extends SupperClass with MixinOne, MixinTwo, MixinThree {
  ......
}

Mixin的使用有哪些约束呢?

  1. Mixin不能继承其他Mixin或者抽象类。
  2. Mixin不能有构造方法,也就是Mixin不能被实例化。

Mixin限定/继承其他类型(on)

为了更好的维护Mixin这些可复用的代码,我们有时需要严格限定使用Mixin的类型,通过on关键字达到目的。

代码样例:如下代码,MixinFine通过on关键字限定使用它的类型是SupperClass,凡是使用MixinFine的类,必须extends继承SupperClass这个Mixin限定的类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class SupperClass {
  ......
}

mixin MixinFine on SupperClass {
  ......
}

class ClassFine extends SupperClass with MixinFine {
  ......
}

mixin class介绍和使用(类+Mixin)

我们通过mixin定义一个Mixin,通过class定义一个类;那么通过mixin class就可以定义一个mixin和一个类,它们具有相同的名字相同的类型

Mixin和类的所有约束,在mixin class同时生效,包括如下:

  1. Mixin不支持extends继承其他类和with复用其他Mixin,因此mixin class也不能有extends继承其他类和with复用其他Mixin
  2. 普通类不支持通过on关键字限定可使用类型,因此mixin class也不支持on关键字(但是我们可以通过abstract达到此目的)。

代码样例:如下代码,mixin class可通过with关键字当成Mixin被使用,也可通过extends关键字当成类被继承使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
abstract mixin class Musician {
  // 含有abstract方法,使用它的类必须实现本方法
  void playInstrument(String instrumentName);

  void playPiano() {
    playInstrument('Piano');
  }
  
  void playFlute() {
    playInstrument('Flute');
  }
}

class Virtuoso with Musician {
  // with关键字,Musician作为一个Mixin被使用
  void playInstrument(String instrumentName) {
    print('Plays the $instrumentName beautifully');
  }  
} 

class Novice extends Musician {
  // extends关键字,Musician作为一个类被继承
  void playInstrument(String instrumentName) {
    print('Plays the $instrumentName poorly');
  }  
}

扩展问题:Mixin如何解决二义性?(覆盖)

通过上面的说明,一个类可以使用多个Mixin的实现,那么有个问题:他们是如何解决二义性的呢?

样例说明:如下代码,我们有2个Mixin,他们的属性和方法都是相同,同时使用他们时,最终的属性和方法是哪个Mixin的呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
mixin MixinA {
  String className = "MixinA";

  void log() {
  print(className);
  }
}

mixin MixinB {
  String className = "MixinB";

  void log() {
  print(className);
  }
}

class ClassMixinAB with MixinA, MixinB {
}

class ClassMixinBA with MixinB, MixinA {
}

void main() {
  ClassMixinAB mixinAB = ClassMixinAB();
  mixinAB.log();
  // 结果:MixinB

  ClassMixinBA mixinBA = ClassMixinBA();
  mixinBA.log();
  // 结果:MixinA
}

通过上面2个代码样例,基本可以判断:Mixin解决二义性的方式非常粗暴,后面Mixin覆盖前面Mixin!!!

Mixin使用场景:打印State生命周期日志

Mixin通过代码复用,可以应用在很多的应用场景。下面代码样例,可以在Flutter组件生命周期逻辑执行之后,打印响应的日志。

样例代码:LogStateMixin通过on关键字限定/继承了State类型,内部的方法,均通过super代理了State的内容,同时打印相应的日志。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
mixin LogStateMixin<T extends StatefulWidget> on State<T> {

  @override
  void initState() {
    super.initState();
   print("====initState====");
  }
  
  @override
  void dispose() {
   super.dispose();
   print("====dispose====");
  }

  // 其他方法......
}

在凡是想要监听组件的生命周期的组件中,可以使用上面的Mixin即可,无其他侵入代码,特别适合在Flutter应用研发过程中,通过日志观测组件的生命周期:

1
2
3
class _MinePageState extends State<MinePage> with LogStateMixin<MinePage>
  // 我的页面逻辑,无需关心日志....
}

这样在页面初始化、销毁的时候,打印响应的日志。


我的本博客原地址:https://ntopic.cn/p/2023093001


邮箱:obullxl@qq.com
QQ:303630027(老牛啊)
微信:imxulin(奔跑的蜗牛)
支付宝:obullxl@163.com