class Bird{ void fly(){ // 堆代码 duidaima.com } void bear(){ print("ovoid");//卵生 } }再为哺乳动物建立一个类:
class Mammal{ void bear(){ print("viviparous");//胎生 } }大部分情况下这两个类是没有问题的,但是总有个例,比如蝙蝠。它的生育是胎生,但是它像鸟一样会飞,如何继承这两种特性?针对这种情况,dart提供了Mixin机制。下面看看Mixin如何使用。
class A{ void init(){ print("a"); } }然后可以通过with关键字来实现混入,如下:
class MixinObj with A{ }这样MixinObj就继承了init函数,执行MixinObj().init()就会打印出“a”。
abstract class A{ void init(){ print("a"); } }也可以是mixin,如下:
mixin A{ void init(){ print("a"); } }注意with继承的类(A):
class MixinObj with A{ @override void init(){ print("obj"); } }这时候只会打印"obj",但是如果执行了super,如下:
class MixinObj with A{ @override void init(){ super.init(); print("obj"); } }那么A的对应函数也会执行,就会打印“a"和“obj”。
class B{ void init(){ print("b"); } void b(){ print("bb"); } }然后混入MixinObj,如下:
class MixinObj with A, B{ }这样MixinObj不仅有init函数,还多了一个b函数。但是这里有一个问题,A和B都有init函数,那么在不重写的情况下执行哪个?答案是最后一个生效,所以是执行了B的init函数。同样如果重写了但是执行了super,也会执行B的init函数。这是Mixin的原则,如果有冲突的话,后面的会优先于前面的,如果没有冲突则会全部保留。这里的优先于如何理解?我们后面深入分析。
class MixinObj extends A with B{ }同样A和B都有init,这时候依然会执行B的init函数。同理如果重写其实也是重写B的init函数。
class MixinObj extends A with B implements C{ }这里C是一个抽象类,有一个init抽象函数。执行后发现还是B的init函数生效了,所以implements不影响with,而with会影响extends。为什么?后面重点分析。
class C{ void init(){ print("c"); }; }然后修改MixinObj:
class MixinObj extends C with A, B{ @override void init(){ super.init(); print("obj"); } }然后运行起来,发现打印出来的是“b”和"obj",super.init()竟然执行的不是C的init函数。为了搞清楚这里面的关系,我们需要从编译生成的文件源码入手。我这里是通过Web运行的,运行后可以在开发者工具的Source中找到源码,如图:
const C_A$36 = class C_A extends MixinTest.C {}; (C_A$36.new = function() { }).prototype = C_A$36.prototype; dart.applyMixin(C_A$36, MixinTest.A); const C_B$36 = class C_B extends C_A$36 {}; (C_B$36.new = function() { }).prototype = C_B$36.prototype; dart.applyMixin(C_B$36, MixinTest.B); MixinTest.MixinObj = class MixinObj extends C_B$36 { init() { super.init(); core.print("obj"); } };可以看到新生成了两个类C_A$36和C_B$36,这两个类就是分别基于A和B生成的(dart.applyMixin(C_A$36, MixinTest.A)),这里可以明显看到MixinObj继承了B,B又继承了A,A才继承了C,这样就可以很好理解上面提到的几个原则,为什么右边的优先于左边的,这个优先于实际上就是一个继承链,而extends则在这个继承链的尾端。所以也理解了super执行的不是extends父类的方法。
而上面我提到过with后面的类是不允许extends继承的,所以就不会干扰整个继承链路,就不用考虑中间还有继承的情况了。简单来说,Mixin就是将类和它的父类(如果没有就是Objecr)的继承关系之间又插入了一些继承关系,这些继承的类的顺序是从右向左的。正是这个继承链才实现了Mixin所谓的多继承。
class MixinBase{ void init(){ print("base"); } }然后定义一个Mixin类,如下:
mixin MixinA on MixinBase{ @override void init(){ super.init(); print("mixina"); } }这里我们来看看生成的源码:
MixinTest.MixinA = class MixinA extends MixinTest.MixinBase {}; MixinTest.MixinA[dart.mixinOn] = MixinBase => class MixinA extends MixinBase { init() { super.init(); core.print("mixina"); } }; dart.addTypeTests(MixinTest.MixinA); dart.addTypeCaches(MixinTest.MixinA); MixinTest.MixinA[dart.implements] = () => [MixinTest.MixinBase]; dart.setLibraryUri(MixinTest.MixinA, I[0]);可以看到在实际处理中就是将MixinA转化成一个类然后继承MixinBase,所以在MixinA可以用super关键字。
class MixinObj with MixinBase, MixinA { @override void init(){ super.init(); print("obj"); } }上面执行结果,依次打印“base”,“mixina”,“obj”,因为MixinObj和MixinA都调用了super。
mixin MixinB on MixinBase { @override void init(){ super.init(); print("mixinb"); } }然后修改MixinObj:
class MixinObj with MixinBase, MixinA, MixinB{ @override void init(){ super.init(); print("obj"); } }这里根据上面的原则,MixinBase必须在另外两个的前面,否则报错。执行后依次打印“base”、“mixinb”、“mixina”、“obj”,通过源码可以看到:
const MixinBase_MixinA$36 = class MixinBase_MixinA extends MixinTest.MixinBase {}; (MixinBase_MixinA$36.new = function() { }).prototype = MixinBase_MixinA$36.prototype; dart.applyMixin(MixinBase_MixinA$36, MixinTest.MixinA); const MixinBase_MixinB$36 = class MixinBase_MixinB extends MixinBase_MixinA$36 {}; (MixinBase_MixinB$36.new = function() { }).prototype = MixinBase_MixinB$36.prototype; dart.applyMixin(MixinBase_MixinB$36, MixinTest.MixinB); MixinTest.MixinObj = class MixinObj extends MixinBase_MixinB$36 { init() { super.init(); core.print("obj"); } };可以看到虽然,MixinA和MixinB都继承(on)MixinBase,但是编译后就打破了这种直接继承的关系,保持之前的继承链逻辑,因为MixinBase一定在MixinA和MixinB前面,所以它还是这两个类的父类,只是不一定是直接父类,所以并不影响。这也是为什么一定要有MixinBase且必须在它俩前的原因。