本文參考並翻譯至: medium.com/flutter-com…
什麼是Mixins
Mixins are a way of reusing a class's code in multiple class hierarchies.
Mixins的字面意思是混入的意思,官方給出的定義是:Mixins是在多繼承層次中重用程式碼的一種方式。
mixin是通過普通的類宣告隱式定義的,要使用mixin,需要使用with關鍵字來實現。 mixin的使用非常簡單,通過下面的例子來看下mixin的使用:
class MixinClass {
void method() {
print("mixin method");
}
}
class User with MixinClass {
}
複製程式碼
在我們的User類中混入MixinClass類,我們就可以使用MixinClass類中的方法。輸出User().method()將會列印出mixin method。
Mixins的詳細用法
如果只是在我們的類中混入一個類,使用起來非常簡單。但是Mixins在特殊情況下的使用,並不那麼簡單,下面我將就其進行詳細說明。
1、混入類中的順序
首先,我們看一個例子
// 父類
class Super {
void method() {
print("Super class method");
}
}
// 混入類1
class M1 {
void method() {
print("M1 class method");
}
}
// 混入類2
class M2 {
void method() {
print("M2 class method");
}
}
// 子類1實現
class Child1 extends Super with M1, M2 {}
// 子類2實現
class Child2 extends Super with M2, M1 {}
void main() {
Child1().method();
Child2().method();
}
複製程式碼
在上面的這個例子中,Child1和Child2都是混入了M1和M2類,但是M1和M2的順序是不一樣的,執行他們的輸出結果:
M2 class method
M1 class method
複製程式碼
我們可以看出來,mixins宣告的順序影響了方法的輸出結果,同時後面mixins的類方法會覆蓋前面mixins類的方法,針對這種情況,Lasse R.H.Nielsen大神給出瞭解釋:
Mixins in Dart work by creating a new class that layers the implementation of the mixin on top of a superclass to create a new class — it is not “on the side” but “on top” of the superclass, so there is no ambiguity in how to resolve lookups.
複製程式碼
翻譯成中文為:在Dart語言中,Mixins通過建立一個新類來工作,這個新類將mixin的實現層放在了父類之上。這裡重點強調了這個新類是在父類之上,並不是在旁邊。因此,在解析查詢方面沒有任何歧義。
結合Lasse R.H.Nielsen大神的解釋,我們重新看下這段程式碼:
class Child1 extends Super with M1, M2 {}
class Child2 extends Super with M2, M1 {}
複製程式碼
上面這段程式碼可以等價於:
// Child1
class Mixin1_1 => Super with M1;
class Mixin1_2 => Mixin1_1 with M2;
class Child1 extends Mixin1_2;
// Child2
class Mixin2_1 => Super with M2;
class Mixin2_2 => Mixin2_1 with M1;
class Child2 extends Mixin2_2;
複製程式碼
通過這樣寫,我們基本上已經找到了上面輸出結果的原因了。這些新類建立在父類和子類中間,是一個mix_in類,並沒有表現出多重繼承。
Lasse R.H.Nielsen大神又給出了這麼一種解釋:
Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear.
複製程式碼
這裡翻譯成中文為:Mixins並不是傳統意義上實現多重繼承的一種方式。Mixin是實現抽象和重用一系列方法和狀態的一種方式。Mixins和擴充套件類中的重用是相似的,Mixins也和單繼承相容,它是一種線性關係。
注意:mixins的順序代表著從父類到子類繼承的順序。
通過上面的解釋,我們繼續剛才的例子,如果我們在Child1或者Child2中實現了method方法
class Child1 extends Super with M1, M2 {
void method() => print("Child1 class method");
}
class Child2 extends Super with M2, M1 {
void method() => print("Child2 class method");
}
複製程式碼
執行後的輸入結果同樣也是顯而易見的:
Child1 class method
Child2 class method
複製程式碼
最後,我們用繼承關係圖(並不是真正的繼承關係,想象成繼承關係)更加直觀的表示下這個例子:
2、混入類中新增限定
首先,我們來看一個例子
abstract class Super {
void method() => print("Super class method");
}
mixin MixinClass on Super {
void method() => print("Mixin class method");
}
class Child extends Super with MixinClass {}
複製程式碼
在這個例子中我們通過mixin關鍵字宣告瞭混入類Mixin,通過關鍵字on新增了父類限制,這意味著如果一個類想要引入這個混入類,這個類必須繼承或者實現這個父類。 在這個例子中如果寫成這樣:
class Child with MixinClass {}
複製程式碼
則會報編譯錯誤:
'MixinClass' can't be mixed onto 'Object' because 'Object' doesn't implement 'MixinClass'.
Try extending the class 'MixinClass'
複製程式碼
現在我們繼續修改下這個例子,給混入類新增super方法
mixin MixinClass on Super {
void method() {
super.method();
print("Mixin class method");
}
}
複製程式碼
執行Child().method()後輸出為:
Super class method
Mixin class method
複製程式碼
回過頭去看下1、混入類中的順序中的繼承關係圖,那麼得出這個結果就是顯而易見的。
WidgetsFlutterBinding中mixins的應用
在前面我們學習到了Mixins使用,Flutter中關於Mixins的最重要的使用就是WidgetsFlutterBinding類,WidgetsFlutterBinding在Flutter進行初始化的時候建立,依次進行了手勢、排程、繪製等的繫結。我們這次的目的就是說明下各個Binding的執行順序。 WidgetsFlutterBinding具體實現如下:
// 1、BindingBase
abstract class BindingBase {
BindingBase() {
initInstances();
}
}
// 2、GestureBinding
mixin GestureBinding on BindingBase {
void initInstances() {
super.initInstances();
}
}
// 3、WidgetsFlutterBinding
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
}
複製程式碼
針對以上程式碼,我們分析過程如下:
- 定義了一個抽象類BindingBase,其建構函式執行了初始化initInstances()。
- 定義了一個混入類GestureBinding(ServuceBinding等類實現原理相同),新增了父類限制BindingBase,引入類中必須實現繼承/實現BindingBase類。
- 定義了一個實現類WidgetsFlutterBinding,繼承BindingBase,混入了GestureBinding、ServiceBinding等類。
- Flutter初始化時執行WidgetsFlutterBinding.ensureInitialized()單例方法,建立WidgetsFlutterBinding物件,執行其建構函式,這裡執行的是BindingBase建構函式。
- BindingBase建構函式執行initInstance(),通過前面繼承關係圖可知,繼承關係如下:WidgetsFlutterBinding->WidgetsBinding->RendererBinding->...->GestureBinding->BindingBase。執行的是WidgetsBinding的initInstance()方法。
- WidgetsBinding中initInstance()方法呼叫了super.initInstance()方法,最終initInstance()執行順序為GestureBinding->ServiceBinding->...->WidgetsBinding。
總結
通過以上我們瞭解到了Mixins的用法,以及其在WidgetsFlutterBinding類中的使用。通過閱讀本篇文章希望能對大家瞭解Mixins有所幫助。新人第一次嘗試寫文章,其中不當的地方也歡迎大家指正。