前言
mixin是dart2.1版本之后引入的新的語法特性,它和abstract功能差不多,但是又比abstract有更多的特性。接下來通過代碼來分別講述abstract和mixin的區(qū)別
1、mixin可減少實(shí)現(xiàn)多繼承時(shí)的代碼冗余
假設(shè)有一個(gè)接口Walk,它有一個(gè)walk()方法,有一個(gè)類Person要實(shí)現(xiàn)該方法,那么用abstract和mixin的實(shí)現(xiàn)分別為:
abstract實(shí)現(xiàn)
abstract class Walk {
walk(){}
}
// 如果是單繼承,那么這里為walk()的默認(rèn)實(shí)現(xiàn)
class Animal extends Walk {
}
// 這里是實(shí)現(xiàn)接口,所以必須實(shí)現(xiàn)walk方法
class Person implements Walk{
@override
walk() {
}
}
abstract實(shí)現(xiàn),它的語法特性為:
1、表示抽象類,即相當(dāng)于c++中的接口,通過implements實(shí)現(xiàn)接口,一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
2、它的方法既可以沒有函數(shù)體也可以有函數(shù)體,實(shí)現(xiàn)接口時(shí)必須要實(shí)現(xiàn)此方法否則報(bào)錯(cuò)
3、它也可以通過extends關(guān)鍵字實(shí)現(xiàn)單繼承(如果定義了默認(rèn)方法,則子類不必實(shí)現(xiàn)該方法)
mixin實(shí)現(xiàn)
mixin Walk_mixin {
walk() {}
}
// 因?yàn)閃alk_mixin有默認(rèn)實(shí)現(xiàn),所以這里可以不實(shí)現(xiàn)
class PersonMixin with Walk_mixin {
}
1、通過with實(shí)現(xiàn)接口,一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
2、它的方法既可以沒有函數(shù)體也可以有函數(shù)體,當(dāng)接口有函數(shù)體時(shí)類在實(shí)現(xiàn)接口時(shí)可以選擇接口的默認(rèn)實(shí)現(xiàn)
所以abstract修飾的類既可以表示接口又可以用于單繼承,而mixin只能用于接口,其次mixin在給出了方法的默認(rèn)實(shí)現(xiàn)后實(shí)現(xiàn)該接口的類可以不用再次實(shí)現(xiàn)該方法,而abstract則必須要實(shí)現(xiàn),故mixin可以減少代碼冗余
mixin和abstract不可同時(shí)使用
2、mixin不支持單繼承
abstract關(guān)鍵字在被當(dāng)做接口使用時(shí)是支持繼承的,即通過extends關(guān)鍵字實(shí)現(xiàn)接口的繼承,代碼如下:
// 飛翔
abstract class Flying{
flying();
}
// 高空飛翔
abstract class HighFlying extends Flying{
highFlying();
}
class Bird implements HighFlying {
@override
flying() {
}
@override
highFlying() {
}
}
上面HighFlying繼承于Flying接口,所以HighFlying相當(dāng)于有了兩個(gè)方法flying()和highFlying()。那么Bird實(shí)現(xiàn)了HighFlying則必須實(shí)現(xiàn)這兩個(gè)方法
mixin關(guān)鍵字繼承
mixin Flying_mixin{
flying() {
print("Flying_mixin");
}
}
// 高空飛翔
mixin HighFlying_mixin on Flying{
highFlying() {}
}
// 高空飛翔;此種方式實(shí)現(xiàn)接口的多繼承是錯(cuò)誤的
mixin HighFlying_mixin2 on Flying_mixin{
highFlying();
}
class BirdMixin extends Flying with HighFlying_mixin {
@override
flying() {
}
}
1、mixin不可繼承mixin接口,但它可以通過on關(guān)鍵字來繼承abstract class修飾的接口(可以試驗(yàn),如果將上面的HighFlying_mixin2放開,那么會報(bào)錯(cuò))
2、mixin通過on關(guān)鍵字繼承class修飾的類,那么此時(shí)with后面的mixin類必須要與當(dāng)前類繼承自同一父類
即這里的BirdMixin和HighFlying_mixin都繼承于Flying抽象類。
3、mixin實(shí)現(xiàn)的多個(gè)接口中有同名的方法
還是以上面圖中的繼承關(guān)系為例,假設(shè)又多了一個(gè)接口MyFlying,它里面也有一個(gè)flying();方法,那么當(dāng)某個(gè)類同時(shí)實(shí)現(xiàn)Flying和MyFlying兩個(gè)接口,這個(gè)類的實(shí)例調(diào)用此方法時(shí)是調(diào)用的哪個(gè)接口的方法呢?根據(jù)官方的說法,有兩種情況:
1、類未實(shí)現(xiàn)接口的這個(gè)方法,那么將采用距離with關(guān)鍵字越遠(yuǎn)的類的實(shí)現(xiàn)方法
2、類實(shí)現(xiàn)了接口的這個(gè)方法,那么將采用自身的實(shí)現(xiàn)
mixin Flying_mixin{
flying() {
print("Flying_mixin");
}
}
mixin MyFlying_mixin {
flying() {
print("MyFlying ");
}
}
class HighBird with Flying_mixin,MyFlying_mixin{
@override
flying() {
super.flying();
print("調(diào)用的方法");
}
}
4、mixin也可以實(shí)現(xiàn)abstract class修飾的接口
假設(shè)某個(gè)mixin接口A實(shí)現(xiàn)了一個(gè)abstract class修飾的接口,另外一個(gè)mixin接口B又通過on關(guān)鍵字繼承了該abstract class
修飾的接口,那么類在使用with關(guān)鍵字實(shí)現(xiàn)這兩個(gè)mixin接口時(shí),A必須寫在B的前面,如下
abstract class HitTest{
hitTest(){
print("hitTest");
}
}
//GestureBinding
mixin GestureBinding implements HitTest{
@override
hitTest() {
}
}
//RendererBinding
mixin RendererBinding on HitTest{
@override
hitTest() {
// TODO: implement hitTest
return super.hitTest();
}
}
// 因?yàn)閣ith關(guān)鍵字和implement關(guān)鍵字不能同時(shí)使用,這里采用取巧的辦法,通過Mixin來實(shí)現(xiàn)接口,然后
// 用with實(shí)現(xiàn)這個(gè)mixin接口,這樣相當(dāng)于類間接實(shí)現(xiàn)了接口
class WidgetsFlutterBinding with GestureBinding,RendererBinding {
@override
hitTest() {
// TODO: implement hitTest
return super.hitTest();
}
}
前面說到mixin通過on關(guān)鍵字繼承abstract class修飾的接口時(shí),當(dāng)被類繼承時(shí)二者必須繼承于同一個(gè)類,否則會報(bào)錯(cuò),這里給出了另外一種寫法,即如果mixin實(shí)現(xiàn)了abstract class修飾的類,那么就相當(dāng)于默認(rèn)實(shí)現(xiàn)了類也繼承了這個(gè)
abstract class修飾的類