作者: | 来源:互联网 | 2023-08-24 19:59
会带着以下几个问题来分享mixin的相关内容
- 什么是mixin?
- 为什么需要mixin?
- 怎么样使用?
- 什么场景下使用?
什么是mixin
官方:Mixins are a way of reusing a class’s code in multiple class hierarchies
mixin是在多个类层次结构中重用类代码的一种方法。 这种描述看起来跟继承没有太多的区别。我们要可以通过继承的方式从父类那得到功能的重用,但是这种方式会有这么几个问题:1、需要在多个类中实现行为,dart不支持多继承,通过lmplement实现多个接口类,无法获取到父类的实现,需要在子类内实现。2:继承会存在多重继承带来的歧义 。 下面举个例子:
图片来自:https://medium.com/flutter-community/dart-what-are-mixins-3a72344011f3
我们这里有一个称为Animal的超类,它 具有三个子类(Mammal,Bird和Fish)。在底部,我们有具体的类。小方块代表行为。例如,蓝色正方形表示具有这种行为的类的实例可以游泳。
有些动物有共同的行为:猫和鸽子都可以走路,但猫不能飞(Nyan Cat except除外)。这些行为与该分类正交,因此我们无法在超类中实现这些行为。
如果一个类可以有多个超类,这很容易,我们可以创建其他三个类:Walker,Swimmer,Flyer。在那之后,我们只是要继承鸠和猫从沃克类。但是在Dart中,每个类(除外Object
)都只有一个超类。除了可以从Walker类继承之外,我们可以实现它,就好像它是一个接口一样,但是我们必须在多个类中实现行为,因此这不是一个好的解决方案。实际上 走路这行为我们只需要写一遍就可以了,但是在dart中我们去使用implement来去继承多个类是,父类的方法我们是无法访问的,子类需要在实现一遍。这显然不是一个很好的方式。
多重继承歧义:当Animal里有个walk方法,Manmmal里也有walk方法,在Cat里调用super.walk()方法是就会产生歧义,无法明确调用谁的walk方法。
那么mixin是怎样解决这些问题的呢?我们先来看看mixin是怎么使用的吧
void main() {
Dove dove = Dove();
dove.walk();
dove.fly();
}
abstract class Animal {}
abstract class Bird extends Animal {}
abstract class Walk {
void walk() {
print("Walk Walk");
}
}
abstract class Fly {
void fly() {
print("Fly Fly");
}
}
class Dove extends Bird with Walk, Fly {}
通过with关键字我们就很好的将 走,飞 两个行为”继承“过来的。那么mixin又是如何解决多重继承歧义的呢?我们来看看下面的代码:
void main() {
Dove dove = Dove();
dove.walk();
}
abstract class Animal {}
abstract class Bird extends Animal {}
class AnimalWalk {
void walk() {
print("AnimalWalk Walk");
}
}
class PersonWalk {
void walk() {
print("PersonWalk Walk");
}
}
class Dove extends Bird with PersonWalk, AnimalWalk {
// @override
// void walk() { // 当注释未打开是 打印为 AnimalWalk Walk,当Dove extends Bird with AnimalWalk,PersonWalk时打印为PersonWalk Walk,当子类自己重写walk时 打印为Dove walk
// print("Dove walk");
// }
}
上面的例子可能不太恰当但是可以说明问题,也就在walk中最终执行谁的walk取决于 1、子类实现了walk,执行子类的 2、子类未实现,会执行with最后一个父类的walk方法。这个跟with 的顺序有关。我们可以理解为
Bird–继承—PersonWalK—继承–AnimalWalk—Dove。这个顺序,那么重写的方法的调用链就是反过来:
Dove—AnimalWalk–PersonWalK–Bird.。其实PersonWalk,AnimalWalk之间是没有关系的,但是有共同的方法,通过这种方式就能很好的重用方法,和避免调用歧义了。
使用方式 关键字顺序
extends => with => implements
class Dog extends Animal with Person implements Fly {}
mixin 修饰的类有几个限制:
- 类不允许有构造方法
- class 修饰的类如果想要通过with使用mixin特性,则必须是继承object的对象
- 进行mixin的类他们必须有同一个Superclass
- mixin 修饰的类可以使用 on 关键字来进行继承操作(如下:)
void thinking() {
print("person thinking");
}
}
mixin A on Person {
void thinking() {
// super.thinking();
print("A thinking");
}
}
mixin B on Person {
void thinking() {
super.thinking();
print("B thinking");
}
}
与extends的区别
- 1)extends 方法必须有依赖顺序, mixin本身没有
- 2)extends 的类型只与直接直系关系有关 , mixin 满足 extends , with , implements 的所有类型
- 3)mixin的实现方式将减少无用的由于extends或者implements所产生的无用代码
- 4)dart中实现mixin概念使用的是extends的方式,但两者的设计理念完全不是一回事
注意点
- 1)通过mixin想要达到约束使用顺序的能力,必须要遵循mixin的继承链顺序
- 2)mixin使用的前提是统一超类
什么情况下会使用它
- 1)如果遇到需要继承多个父类达到使用方法的目的, 此时可以使用 mixin
- 2)当代码复用的情况不适合使用 继承,工具类的时候也可以考虑使用mixin
flutter中的典型使用
- widget 的父类 DiagnosticableTree
- class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding
以上就是mixin的内容,欢迎拍砖,交流!