Dart語言集合了現代編程語言的衆多優勢,Mixin繼承機制也是其一。但針對Java程序員來講,可能不是一會兒能理解的,好比我第一次看到的時候,也迷迷糊糊了半天——這是啥玩意???java
要說Mixin,可能寫成MixIn會更好理解,翻譯回來就是混入,固然你執意說這是一種「迷信」繼承機制,那也沒轍。git
下面將從一個實際情景入手,對比Java和Dart的實現,以便更好理解Dart的mixin。程序員
咱們先來描繪這麼一個職業關係圖:
github
職業關係圖編程
從圖中能夠梳理出如下關係:編程語言
而以上的工程師、教師都是社會的工做者。ide
那麼接下來咱們分別使用Java和Dart來實現這個關係類。ui
注意:接下來的這篇文章中爲了方便表達意義,將全部類寫在一個文件裏面,請暫時忽略代碼不規範細節。而且Dart在本文不會使用語法糖寫法。spa
從層級出發,能夠寫出Java版本實現以下:翻譯
//工做者 abstract class Worker { public abstract void doWork();//工做者須要工做 } //工程師 class Engineer extends Worker { @Override public void doWork() { System.out.println("工程師在工做"); } } //教師 class Teacher extends Worker { @Override public void doWork() { System.out.println("教師在教學"); } } //軟件工程師 class SoftwareEngineer extends Engineer { } //建築工程師 class BuildingEngineer extends Engineer { } //美術教師 class ArtTeacher extends Teacher { } //IT教師 class ITTeacher extends Teacher { }
//工做者 abstract class Worker { void doWork();//工做者須要工做 } //工程師 class Engineer extends Worker { void doWork() { print('工程師在工做'); } } //教師 class Teacher extends Worker { void doWork() { print('教師在教學'); } } //軟件工程師 class SoftwareEngineer extends Engineer { } //建築工程師 class BuildingEngineer extends Engineer { } //美術教師 class ArtTeacher extends Teacher { } //IT教師 class ITTeacher extends Teacher { }
從上面實現能夠看出,兩個實現並沒什麼卵區別好咩。。。。。。
嗯,目前來講確實是這樣的,由於Dart也是單繼承。
由於上面的場景是在是too young too simple了,下面開始擴展一些場景。
仍是剛剛那張關係圖,咱們開始思考這些職業他們都具備什麼能力。
因而我給這些職業虛擬瞭如下能力:
職業 | 能力 |
---|---|
軟件工程師 | 軟件設計、修電腦 |
建築工程師 | 手繪 |
美術教師 | 手繪、書法 |
IT教師 | 修電腦 |
他們的關係圖以下:
經過圖形或表格能夠看出,軟件工程師和IT教師都具有修電腦的能力,建築工程師和美術教師都具有手繪的能力,可是這些能力都是他們特有的,不是工程師或者教師具有的能力,因此不能在他們的父類中實現。
那麼這個時候咱們就考慮到一個東西——接口。
以軟件工程師和IT教師爲例:
他們都具有修電腦的能力:
interface CanFixComputer { void fixComputer(); } interface CanDesignSoftware { void designSoftware(); } //軟件工程師 class SoftwareEngineer extends Engineer implements CanFixComputer, CanDesignSoftware { @Override public void fixComputer() { System.out.println("修電腦"); } @Override public void designSoftware() { System.out.println("設計軟件"); } } //IT教師 class ITTeacher extends Teacher implements CanFixComputer { @Override public void fixComputer() { System.out.println("修電腦"); } }
至關標準的實現了
咱們知道Dart是沒有interface這種東西的,但並不覺得着這門語言沒有接口,事實上,Dart任何一個類都是接口,你能夠實現任何一個類,只須要重寫那個類裏面的全部具體方法。
咱們只須要將上面的interface 修改爲 abstract class,就是dart中的實現了。
可是咱們發現,fixComputer這個接口被繼承了兩次,而且兩次的實現都是同樣的,這裏就出現了代碼重複和冗餘的問題。怎麼辦呢?在java中咱們有接口的default實現來解決這個問題(這是一個java8出現的不得已的方案。)
這個時候mixin的做用就出現了
abstract class CanFixComputer { void fixComputer() { print('修電腦'); } } abstract class CanDesignSoftware { void designSoftware() { print('設計軟件'); } } //軟件工程師 class SoftwareEngineer extends Engineer with CanFixComputer, CanDesignSoftware { } //IT教師 class ITTeacher extends Teacher with CanFixComputer { } main() { ITTeacher itTeacher = new ITTeacher(); itTeacher.doWork(); itTeacher.fixComputer(); SoftwareEngineer softwareEngineer = new SoftwareEngineer(); softwareEngineer.doWork(); softwareEngineer.fixComputer(); softwareEngineer.designSoftware(); }
能夠看到,這裏再也不用implements
,更不是extends
,而是with
。
並且,每一個具備某項特性的類再也不須要具體去實現一樣的功能,接口是無法實現功能的,而經過繼承的方式雖然能實現功能,但已經有父類,同時不是一個父類,又不能多繼承,因此這個時候,Dart的Mixin機制就比Java的接口會高效,開發上層的只須要關心當前須要什麼特性,而開發功能模塊的關心具體要實現什麼功能。
既然是with,那應該也會有順序的區別,
思考一個問題:若是同時with兩個類,但兩個類中有一樣的一個方法的不一樣實現,那麼這個時候應該使用的是哪個類的方法?
下面以一個簡單的Demo來講明這個問題:
class First { void doPrint() { print('First'); } } class Second { void doPrint() { print('Second'); } } class Father { void doPrint() { print('Father'); } } class Son1 extends Father with First,Second { void doPrint() { print('Son1'); } } class Son2 extends Father with First implements Second { void doPrint() { print('Son2'); } } main() { Son1 son1 = new Son1(); son1.doPrint(); Son2 son2 = new Son2(); son2.doPrint(); }
那麼這個程序運行後,將會在控制檯輸出以下:
1 2 |
Son1 Son2 |
能夠看到,不管是extends、implements仍是mixin,優先級最高的是在具體類中的方法。
咱們稍微改一下上面的例子:
class First { void doPrint() { print('First'); } } class Second { void doPrint() { print('Second'); } } class Father { void doPrint() { print('Father'); } } class Son1 extends Father with First,Second { } class Son2 extends Father with First implements Second { } main() { Son1 son1 = new Son1(); son1.doPrint(); Son2 son2 = new Son2(); son2.doPrint(); }
這個時候控制檯輸出以下:
1 2 |
Second First |
能夠看到,其實在Son2中implements只是說要實現他的doPrint()
方法,這個時候其實具體實現是First中Mixin了具體實現。
而Mixin的具體順序也是能夠從代碼倒過來看的,最後mixin的優先級是最高的。
PS: dart中有個關鍵字 mixin 能夠用來替換上面的 class,這個類表示專門用來作mixin的。
另外在mixin類中咱們還以使用這樣使用
mixin MusicalPerformer on Musician { // ··· }
這個表示只有類Musician可以使用這個mixin類。