当前位置:网站首页>【Dart】dart之mixin探究
【Dart】dart之mixin探究
2022-08-01 20:04:00 【allanGold】
由于dart中是没有interface的,在dart中我们需要定义接口的话用的是class关键字
implements是把某个class当做接口来实现要求我们重写这个class的所有方法
注意:implements会将class的实现抹掉就不存在默认实现一说,而dart也是不允许多继承的。
extends表示继承某个class,可以继承父类实现了的方法
mixin实际上也是面向对象编程中的概念,用户与Mixin不是“is-a”的关系,而是“-able”关系
Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类。[1]Mixin有时被称作"included"而不是"inherited"。mixin为使用它的class提供额外的功能,但自身却不单独使用(不能单独生成实例对象,属于抽象类)。因为有以上限制,Mixin类通常作为功能模块使用,在需要该功能时“混入”,而且不会使类的关系变得复杂。
dart语言里面我们可以使用with关键字实现mixin,将一个或者多个class混入另一个类:
class Base1 {
void foo1() {
print("foo1");
}
}
class Base2 {
void foo2() {
print("foo2");
}
}
class Child2 with Base1, Base2 {
}
没错,通过with多个类,可以实现类似多继承的效果。
既然允许with多个类,那么如果这些类中有个相同方法,那会出现什么事情?
实际上kotlin、java8使用接口的默认实现也会出现一样的问题,他们的处理方法是当出现相同方法的时候实现类需要手动指定使用哪个接口的默认实现,要不然编译会报错:
// java8
interface IBase1 {
default void foo() {
System.out.println("1");
}
}
interface IBase2 {
default void foo() {
System.out.println("2");
}
}
class Child implements IBase1, IBase2 {
@Override
public void foo() {
IBase2.super.foo();
}
}
//kotlin
interface IBase1 {
fun foo() {
println("1")
}
}
interface IBase2 {
fun foo() {
println("2")
}
}
class Child : IBase1, IBase2 {
override fun foo() {
super<IBase2>.foo()
}
}
必须提到的是:无论是 extends、implements 还是 mixin,优先级最高的是在具体类中的方法。
线性化
而在dart中with里面越后面的类优先级越高:
class Base1 {
void foo() {
print("1");
}
}
class Base2 {
void foo() {
print("2");
}
}
class Base3 {
void foo() {
print("3");
}
}
class Child extends Base1 with Base2, Base3 {}
这个时候调用Child.foo方法实际会优先调用Base3.foo。原因是dart实际是通过创建中间类继承实现的mixin,上面的代码相当于:

通过从左到右的顺序生成中间父类去继承将extends、with线性化成一个单继承链。所以Base2、Base3实际上不是Child的父类
mixin关键字
在上面的例子中我们使用普通的class去with,但dart实际上提供了一个mixin关键字,它定义了不能实例化、也不能extends只能with的类:
mixin Base {
}
// 编译失败: mixin类不能extends
// class Child extends Base {
//
// }
// 编译成功: mixin类可以with
class Child with Base {
}
void main() {
// 编译失败: mixin类不能实例化
// Base()
}
这样的类实际上和java、kotlin里面的interface已经很像了。
另外我们可以通过mixin … on 限定某个类只能由某些类去with:
class Base1 {
void foo() {
print("1");
}
}
class Base2 {
void foo() {
print("2");
}
}
mixin Base3 on Base1 {
void foo() {
super.foo();
print("3");
}
}
class Child extends Base1 with Base2, Base3 {}
上面的demo中Base3只能由Base1去with,那就以为着这个with Base3的类一定是继承或者with了 Base1,所以可以调用这个类的super.foo方法。要注意的是,这个super.foo并不指定一定调用的是Base1.foo。例如上面的代码调用Child().foo()之后的打印实际上是:
2
3
它们线性化的到的继承关系和前面全是class的代码并没有差别:

从上面的uml图我们就能理解为什么打印是2 3了
理解了这个简单的例子之后我们再来看一个复杂一点的例子:
class Base1 {
void foo1() {
print("Base1.foo1");
foo2();
}
void foo2() {
print("Base1.foo2");
}
}
mixin Base2 on Base1 {
void foo1() {
super.foo1();
print("Base2.foo1");
}
void foo2() {
print("Base2.foo2");
}
}
class Child with Base1,Base2 {}
void main() {
Child().foo1();
}
它的输出是:
Base1.foo1
Base2.foo2
Base2.foo1
原因是Base2.foo1中的super.foo1实际上调用的是Base1.foo1,而Base1.foo1中的foo2,由于继承的多态特性,调用的是Base2.foo2。
我们可以通过下面uml图辅助理解,注意看继承关系里面是没有Base1、Base2的因为它们都是通过with混入的,并不是Child的父类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fLZsiSq3-1659324422994)(https:upload-images.jianshu.io/upload_images/2199790-7482262610cc24c7.png?imageMogr2/auto-orient/strip|imageView2/2/w/758)]
with的类不能有构造函数
另外,with的class和mixin类型都是不允许有构造函数的,因为mixin机制语义上是向一个类混入其他类的方法或者成员变量,使得我们可以在混合类中访问到混入类的方法或者属性。而混入其他类的构造函数实际上是没有意义的,因为不会有人手动去调用这个混入类的构造函数。
class Base1 {
Base1() {
}
}
// 编译失败: 不能with一个带有构造函数的类
// class Child with Base1 {}
// 编译失败: mixin类型只能with,所以不能有构造函数
// mixin Base2 {
// Base2() {}
// }
参考博客
https://medium.com/flutter-community/dart-what-are-mixins-3a72344011f3
https://www.jianshu.com/p/f4efaa6b8fe6
https://www.jianshu.com/p/fc96bef9beba
https://my.oschina.net/zzxzzg/blog/2962518
边栏推荐
猜你喜欢

【nn.Parameter()】生成和为什么要初始化

正则表达式

Get started quickly with MongoDB

【kali-信息收集】(1.6)服务的指纹识别:Nmap、Amap

第59章 ApplicationPart内置依赖注入中间件

我的驾照考试笔记(1)

专利检索常用的网站有哪些?

【个人作品】记之-串口日志记录工具
![[Personal work] Wireless network image transmission module](/img/64/c0cec74692df7ca05c1a5317e21c9d.png)
[Personal work] Wireless network image transmission module
![[Energy Conservation Institute] Ankerui Food and Beverage Fume Monitoring Cloud Platform Helps Fight Air Pollution](/img/ca/e67c8e2196adb5a078acc44ba5ad6f.jpg)
[Energy Conservation Institute] Ankerui Food and Beverage Fume Monitoring Cloud Platform Helps Fight Air Pollution
随机推荐
18. Distributed configuration center nacos
mysql自增ID跳跃增长解决方案
【无标题】
我的驾照考试笔记(1)
Intranet penetration lanproxy deployment
LTE time domain and frequency domain resources
【Untitled】
"No title"
Redis 做网页UV统计
Software you should know as a programmer
使用微信公众号给指定微信用户发送信息
Compose实战-实现一个带下拉加载更多功能的LazyColumn
XSS靶场中级绕过
二维、三维、四维矩阵每个维度含义解释
【七夕特别篇】七夕已至,让爱闪耀
nacos installation and configuration
【kali-信息收集】(1.3)探测网络范围:DMitry(域名查询工具)、Scapy(跟踪路由工具)
【社媒营销】如何知道自己的WhatsApp是否被屏蔽了?
[Personal work] Wireless network image transmission module
Pytorch模型训练实用教程学习笔记:四、优化器与学习率调整