前言
mixin可以簡單的理解為”已經實作的interface”。以下範例:
1
2
3
4
5
6
7
8
9
10
11
|
mixin CryAbility{
void cry() => print("cry very loud");
}
class Baby with CryAbility{
int age = 0;
}
// 使用時
var baby = Baby();
baby.cry();
|
是否還蠻好懂得呢?接下來更細緻一點介紹mixin的使用方法。
舊版宣告
mixin在舊版的dart中是直接宣告為class,然後只要在想加上mixin的class中使用with關鍵字,就會自動被解析為mixin。
1
2
3
4
5
6
7
8
9
10
11
12
|
// abstract 拿掉亦可執行
abstract class CryAbility{
void cry() => print("cry very loud");
}
class Baby with CryAbility{
int age = 0;
}
// 使用時
var baby = Baby();
baby.cry();
|
不過這樣造成語意不清,身為mixin的class應該只能被with,不應該被實體化。
於是多數人會在mixin class前面加上abstract,以提醒使用者。
為了可讀性,還是盡可能使用新版的mixin關鍵字比較好。
多重實作
如同一個class可以實作多個interface,一個class同樣也可以實作多個mixin。以下範例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
mixin CryAbility{
void cry() => print("cry very loud");
}
mixin EatAbility{
void eat() => print("eat eat eat");
}
class Baby with CryAbility, EatAbility{
int age = 0;
}
// 使用時
var baby = Baby();
baby.cry();
baby.eat();
|
限制實作對象
如果今天想限制只有某些class可以實作mixin,比如說,假如想限制只有Baby可以cry,其他class(例如IronMan)不能cry。那可以用以下的寫法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// on 可以實作的對象
mixin CryAbility on Baby{
void cry() => print("cry very loud");
// 可以使用on對象上的物件
void cryWithAge() => print("A $age year-old baby cry very loud");
}
// ERROR: 注意!!!此處不能with,原因後述。
class Baby {
int age = 0;
}
// 沒問題,GrowthBaby是Baby的一種
class GrowthBaby extends Baby with CryAbility{
int age = 1;
}
// ERROR: IronMan不屬於Baby,編譯器會報錯。
class IronMan with CryAbility{
int iron = 10;
}
// 使用時
var baby = GrowthBaby();
baby.cryWithAge();
|
當限制CryAbility只能on Baby時,CryAbility就有了存取Baby field的能力。因此cryWithAge才能使用age這個Baby的field。
值得一提的是,IronMan報錯不難理解,但為何無法在原始的Baby class上with CryAbility呢? 這牽扯到了mixin這個關鍵字如何被轉譯成舊版的宣告形式的。以下範例
1
2
3
4
5
6
7
8
|
mixin CryAbility on Baby{
void cry() => print("cry very loud");
}
// 等價於
abstract class CryAbility extends Baby{
void cry() => print("cry very loud");
}
|
所以為何CryAbility能使用Baby field? 因為他繼承了Baby。
為何Baby不能with CryAbility? 因為他是CryAbility的super class。
這點在使用上要特別小心。
實作同一個方法
如果實作多個mixin,剛好有同樣的method name,那到底誰會被呼叫呢?
簡單結論是: 最後一個被with的會被呼叫。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mixin CryAbility1{
void cry() => print("cry1");
}
mixin CryAbility2{
void cry() => print("cry2");
}
class Baby12 with CryAbility1, CryAbility2{}
class Baby21 with CryAbility2, CryAbility1{}
main(){
Baby12().cry(); // 輸出: cry2
Baby21().cry(); // 輸出: cry1
}
|
更詳細內容請看參考資料: 【译】Dart | 什么是Mixin
Reference