本篇純為個人見解,可能還有不少沒理解清楚的地方,歡迎大家提出指正哦!
-
這篇本來要跟上一篇一起寫
直到我發現Dart中Mixin的觀念其實多到可以自成一篇QQ
觀念
先來講講一些觀念:
Mixin是物件導向語言中的一種類,不過每種語言中的Mixin類特性不盡相同
Mixin類自帶方法的實現,無須依賴子類(當然子類要override也不是不行啦)
Mixin類責任單一,要寫多種功能請寫多個Mixin類
Mixin並非多重繼承(Multiple Inheritance),也不是接口(Interface),不過功能上蠻像的
在Dart中,可實例化的類與無法實例化的抽象類,都能拿來當作Mixin類
在Dart中,可以使用With這個關鍵字Mixin多個Mixin類,但不破壞單繼承的特性
看完上述這幾點,是不是心裡只有 “馬的,工三小?“
舉個例子
接下來的話就來舉個例子好了
現在有兩種技能: Teach & Drive
而且有兩種職業: Teacher & Driver
現在假設這兩個職業都各持有Teach & Drive這兩個技能
Java v.s. Dart
Java版本:
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| abstract class Human { }
interface Teach { void canTeach(); }
interface Drive { void canDrive(); }
class Teacher extends Human implements Teach, Drive { @Override public void canTeach() { System.out.println("Yes, a human can teach."); }
@Override public void canDrive() { System.out.println("Yes, a human can drive."); } }
class Driver extends Human implements Teach, Drive { @Override public void canTeach() { System.out.println("Yes, a human can teach."); }
@Override public void canDrive() { System.out.println("Yes, a human can drive."); } }
public static void main(String[] args) { Teacher teacher = new Teacher(); teacher.canTeach(); teacher.canDrive(); Driver driver = new Driver(); driver.canTeach(); driver.canDrive(); }
|
Dart版本:
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 26 27 28 29
| abstract class Human { }
class Teach { void canTeach() { print("Yes, a human can teach."); } }
class Drive { void canDrive() { print("Yes, a human can drive."); } }
class Teacher extends Human with Teach, Drive {}
class Driver extends Human with Teach, Drive {}
void main() { Teacher teacher = new Teacher(); teacher.canTeach(); teacher.canDrive(); Driver driver = new Driver(); driver.canTeach(); driver.canDrive(); }
|
輸出均為:
1 2 3 4
| Yes, a human can teach. Yes, a human can drive. Yes, a human can teach. Yes, a human can drive.
|
這裡可以看到在Java版本的兩個職業中,實作方法(技能)時出現重複的程式碼
而這裡Dart版本中的Mixin類自帶方法實現,從而解決了這個問題
(不過Java 8以上的default method也有同樣的效果)
使Mixin類無法實例化
這裡可以使用關鍵字 mixin
1 2 3 4 5 6
| mixin Teach { void canTeach() { print("Yes, a human can teach."); } }
|
或者是改為abstract class
然後給定該類一個private constructor(dash代表私有),並設回傳值為 null
1 2 3 4 5 6 7 8
| abstract class Drive { factory Drive._() => null; void canDrive() { print("Yes, a human can drive."); } }
|
mixin on
現在我們修改一下設定
假設說只有會教書的人能使用Teach這個技能呢?
這時我們可以用到 mixin on
這個關鍵字
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| abstract class Human { }
class WhoCanTeach extends Human { }
mixin Teach on WhoCanTeach { void canTeach() { print("Yes, a teacher can teach."); } }
abstract class Drive { factory Drive._() => null; void canDrive() { print("Yes, a human can drive."); } }
class Teacher extends WhoCanTeach with Teach, Drive { }
class Driver extends Human with Teach, Drive { }
class Driver extends Human with Drive { }
void main() { Teacher teacher = new Teacher(); teacher.canTeach(); teacher.canDrive(); Driver driver = new Driver(); driver.canDrive(); }
|
輸出:
1 2 3
| Yes, a teacher can teach. Yes, a human can drive. Yes, a human can drive.
|
線性化
看一下這個例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Human { String getStatus() => "Full of energy!"; }
class Student { String getStatus() => "I'm tired!"; }
class Engineer { String getStatus() => "I'm dying..."; }
class Me extends Human with Student, Engineer {}
void main() { Me me = new Me(); print(me.getStatus()); }
|
好的,這裡究竟會印出什麼東西來呢?
答案是 “I’m dying…” QQ
先講結論: 越後面的Mixin類優先級別越高,等於是倒過來看啦~
拆解
上面的東西相當於這樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Human { String getStatus() => "Full of energy!"; }
class Student { String getStatus() => "I'm tired!"; }
class Engineer { String getStatus() => "I'm dying..."; }
class HumanWhoIsStudent extends Human with Student {}
class HumanWhoIsStudentAndEngineer extends HumanWhoIsStudent with Engineer {}
class Me extends HumanWhoIsStudentAndEngineer {}
void main() { Me me = new Me(); print(me.getStatus()); }
|
簡單來說,Mixin像是在實現一條線性的繼承鏈
實例化後的類型
一樣是上面的例子
1 2 3 4 5 6 7
| void main() { Me me = new Me(); print(me is Me); print(me is Engineer); print(me is Student); print(me is Human); }
|
輸出: