說(shuō)明
Dart 是不支持多繼承的,但是它支持 mixin,簡(jiǎn)單來(lái)講 mixin 可以 “組合” 多個(gè)類,這樣就極大的減少了代碼冗余。
mixin是面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言中的類,提供了方法的實(shí)現(xiàn)。其他類可以訪問(wèn)mixin類的方法、變量而不必成為其子類。簡(jiǎn)而言之,mixins是普通的類,我們可以從中擴(kuò)展方法(或變量)而不擴(kuò)展類。
示例
定義一個(gè) Person 類,實(shí)現(xiàn)吃飯、說(shuō)話、走路和寫(xiě)代碼功能,同時(shí)定義一個(gè) Dog 類,實(shí)現(xiàn)吃飯、和走路功能。我們定義了幾個(gè) mixin,然后通過(guò) with 關(guān)鍵字將它們組合成不同的類。有一點(diǎn)需要注意:如果多個(gè)mixin 中有同名方法,with 時(shí),會(huì)默認(rèn)使用最后面的 mixin 的,mixin 方法中可以通過(guò) super 關(guān)鍵字調(diào)用之前 mixin 或類中的方法。
class Person {
say() {
print('say');
}
}
mixin Eat {
eat() {
print('eat');
}
}
mixin Walk {
walk() {
print('walk');
}
}
mixin Code {
code() {
print('key');
}
}
class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}
從用法有點(diǎn)類似于Java中的多接口實(shí)現(xiàn),不同點(diǎn)在于,mixin可以有默認(rèn)實(shí)現(xiàn),當(dāng)然Java8中也有了這個(gè)功能。
mixin之線性化
在上面的示例中,我們發(fā)現(xiàn)with關(guān)鍵字后有多個(gè)類。那么這里就產(chǎn)生了一個(gè)問(wèn)題——如果with后的多個(gè)類中有相同的方法,那么當(dāng)調(diào)用該方法時(shí),會(huì)調(diào)用哪個(gè)類里的方法尼?由于距離with關(guān)鍵字越遠(yuǎn)的類會(huì)重寫(xiě)前面類中的相同方法,因此分為以下兩種情況:
- 如果當(dāng)前使用類重寫(xiě)了該方法,就會(huì)調(diào)用當(dāng)前類中的方法。
- 如果當(dāng)前使用類沒(méi)有重寫(xiě)了該方法,則會(huì)調(diào)用距離with關(guān)鍵字最遠(yuǎn)類中的方法。
//BindingBase
abstract class BindingBase {
void initInstances() {
print("BindingBase——initInstances");
}
}
//GestureBinding
mixin GestureBinding on BindingBase{
@override
void initInstances() {
print("GestureBinding——initInstances");
super.initInstances();
}
}
//RendererBinding
mixin RendererBinding{
@override
void initInstances() {
print("RendererBinding——initInstances");
super.initInstances();
}
}
// WidgetsBinding
mixin WidgetsBinding on BindingBase{
@override
void initInstances() {
print("WidgetsBinding——initInstances");
super.initInstances();
}
}
//WidgetsFlutterBinding
class WidgetsFlutterBinding extends BindingBase
with GestureBinding, RendererBinding, WidgetsBinding {
static WidgetsBinding ensureInitialized() {
return WidgetsFlutterBinding();
}
}
//main
main(List<String> arguments) {
var binding = WidgetsFlutterBinding();
binding.initInstances();
}
WidgetsFlutterBinding中并沒(méi)有重寫(xiě)initInstances方法,那么就以最右邊重寫(xiě)該方法的類——WidgetsBinding為主。那么結(jié)果應(yīng)該如下:WidgetsBinding——initInstances
其實(shí)結(jié)果是:
WidgetsBinding——initInstances RendererBinding——initInstances GestureBinding——initInstances BindingBase——initInstances
這是為什么尼?仔細(xì)一點(diǎn)就可以發(fā)現(xiàn),我們?cè)赪idgetsBinding、RendererBinding及GestureBinding中都調(diào)用了父類的initInstances方法,也因此會(huì)一級(jí)一級(jí)往上調(diào)用。如果我們?nèi)∠摼浯a,則會(huì)終止這種調(diào)用方式。這就是線性化。