小白都能看懂的关于Mixins机制的理解

Posted Beason_H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小白都能看懂的关于Mixins机制的理解相关的知识,希望对你有一定的参考价值。

前言

​ 在学习Flutter源码的时候,看到各种复杂的mixin和on,为了便于后续Flutter的学习,这里有必要一起来份详细Dart 的 Mixin机制。

什么是mixins

首先看看官方文档的定义:

Mixins are a way of reusing a class’s code in multiple class hierarchies.

即:Mixins是用来复用多个类之间的代码,减少耦合。

再来看看维基百科对它的定义:

mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法、变量而不必成为其子类。

这两种解释我任务维基百科描述的更通俗一点,下面我们来详细解释:

讲解

假如我们有两个类A,B,现在需要使用mixins定义类T

class T = A with B;
//或
class T extends A with B {}

那么我们得到结果class T是什么样的? 假设我们A类中的所有方法为AM,B类中所有的方法集合叫BM,那么T中的方法集合就为:

BM U (AM-BM)

即:T中的方法为A 和 B类中方法的集合,如果有重复方法,取B中的方法(with 最右侧的方法)

上面伪代码就是最直接简单的方式,相信大家应该都能看懂。下面我们来举个例子详细介绍一下

我们来举几个例子

1. A with B

//A
class A {
  a() {
    print('A.a()');
  }
  b() {
    print('A.b()');
  }
}
//B
class B {
  a() {
    print('B.a()');
  }
}
//Z
class Z extends A with B {}

void main() {
  Z z = Z();
  z.a();
}

根据上面伪代码AM U (AM-BM)讲解(Z的方法为A,B方法集合,有重复方法取with最右边类的方法),得出Z类中最终包含的方法应该是:B.a(),A.b()

代码输出结果是:

B.a()

2. A with B,C

A with B, C可以理解为:(A with B) with C

//A
class A {
  a() {
    print('A.a()');
  }

  b() {
    print('A.b()');
  }
}

//B
class B {
  a() {
    print('B.a()');
  }

  b() {
    print('B.b()');
  }

  c() {
    print('B.c()');
  }
}

//C
class C {
  a() {
    print('C.a()');
  }
}

//Z
class Z extends A with B, C {}

void main() {
  Z z = new Z();
  z.a();
  z.b();
  z.c();
}

根据上面的逻辑整理最终方法集合公式为CM U (BM - CM) U (AM - BM - CM),最终Z包含的方法应该是:C.a(), B.b(), B.c()

代码输出结果是:

C.a()
B.b()
B.c()

下面是重点关注容易被忽略的关于mixin机制里面super的注意事项

abstract class BaseA {
  BaseA() {
    initInstances();
  }

  initInstances() {
    //do nothing
  }
}

mixin B on BaseA {
  @override
  initInstances() {
    super.initInstances();
    print('B');
  }
}

mixin C on BaseA {
  @override
  initInstances() {
    super.initInstances();
    print('C');
  }
}

mixin D on BaseA {
  @override
  initInstances() {
    super.initInstances();
    print('D');
  }
}

class T extends BaseA with B, C, D {
  static void init() {
    T();
  }
}

void main() {
  T.init();
}

相信上面的代码如果删除B,C,D各个类里面的super.initInstances()方法调用就很容易得出结论知道输出结果是:D。

但是这里加上super.initInstances()调用结果却截然不同,我们只需要理解在mixin机制中,每调用一个方法都会类似从最右边开始查找需要调用的方法,一直查找到最左边的基类,一旦找到就停止查找然后调用到该方法。super也是类似,通过super.method调用的方法,会从当前类往左去查找metod方法;所以上面代码的输出结果就是:B,C,D

思考:上面如果我们将B,C,D类中的super.initInstances()和print(’*’)顺序颠倒过来会输出什么

总结

​ 关于Mixins还有很多需要注意的细节,这里我们需要通过demo多多练习,有时候通过Mixin机制我们可以跨越多个类的层次实现代码的重用,特别是Mixins机制中super的使用,在Flutter源码中也经常使用,需要多多练习才能理解透彻。

​ 本文主要是自己通过Demo的 一些理解,如果有不同的见解,欢迎评论交流。

思考

下面模拟Flutter runApp中WidgetsFlutterBinding初始化的方式,思考下输出的是什么:

abstract class BindingBase {
  BindingBase() {
    print('constructor A');
    initInstances();
  }

  initInstances() {
    //do nothing
  }
}

mixin ABinding on BindingBase {
  @override
  initInstances() {
    super.initInstances();
    print('ABinding.initInstances()');
  }
}

mixin BBinding on BindingBase {
  @override
  initInstances() {
    super.initInstances();
    print('BBinding.initInstances()');
  }
}

mixin CBinding on BindingBase {
  @override
  initInstances() {
    super.initInstances();
    print('CBinding.initInstances()');
  }
}

class WidgetsFlutterBinding extends BindingBase
    with ABinding, BBinding, CBinding {
  static void ensureInitialized() {
    WidgetsFlutterBinding();
  }
}

void main() {
  WidgetsFlutterBinding.ensureInitialized();
}

欢迎评论区给出答案讨论

以上是关于小白都能看懂的关于Mixins机制的理解的主要内容,如果未能解决你的问题,请参考以下文章

gitbook 入门教程之小白都能看懂的 Gitbook 插件开发全流程

小白都能看懂的10分钟网络模型知识大全

小白都能看懂的java虚拟机内存区域划分

我的小白女友都能看懂的超简单直接插入排序算法!

小白都能看懂的前后端分离

小白都能看懂的实战教程 手把手教你Python Web全栈开发 (DAY 2)