原文在這裡。寫的不錯,推薦各位看原文。
這裡補充一下Mixin的定義:
只要一個類是繼承自Object
的而且沒有定義構造方法,那麼這個類可以是一個Mixin了。當然,如果你想讓mixin的定義更加的清晰,可以使用mixin關鍵字開頭來定義。具體請參考這裡
原文截圖體會一下風格。
正文
在經典的物件導向程式語言裡一定會有常規的類,抽象類和介面。當然,Dart也有它自己的介面,不過那是另外的文章要說的。有的時候陰影裡潛伏者另外的野獸:Mixin!這是做什麼的,如何使用?我們來一起發現。
沒有mixin的世界
假設你在構建一個模擬野生動物的app,那麼你需要一個Mosquito(蚊子)類。作為一個有預見性的開發人員,你會抽象蚊子們有的共通的東西然後放在一個抽象類裡。
abstract class Insect {
void crawl() {
print('crawling');
}
}
abstract class AirborneInsect extends Insect {
void flutter() {
print('fluttering');
}
void buzz() {
print('buzzing annoyingly')
}
}
class Mosquito extends AirborneInsect {
void doMosquitoThing() {
crawl();
flutter();
buzz();
print('sucking blood');
}
}
複製程式碼
很棒!你已經做到了!新增新的昆蟲就如同微風拂過一樣,根本不會有程式碼的冗餘出現。。。一直到你發現你需要一個Swallow類(就是一種可以吃掉整個蚊子的東西)。
同樣的也有很多鳥類共有的東西,我們可以建立一個Bird類。這個時候問題就出現了 -- 鳥也會振動翅膀!但是,你沒法把flutter方法從AirboneInsect類裡面提取出來組成一個新的類Fluttering。
為什麼?Bird類可以繼承Fluttering類,但是AirboneInsect不可以,它已經繼承了Insect類了。Dart可不支援多繼承(真很好)。
這下,你需要給Bird類新增一個flutter方法了。程式碼冗餘發生了!
abstract class Bird {
void chirp() {
print('chirp chirp');
}
// Duplicate method
void flutter() {
print('fluttering');
}
}
class Swallow extends Bird {
void doSwallowThing() {
chirp();
flutter();
print('eating a mosquito');
}
}
複製程式碼
使用mixin
Mixin的定義是“一種把類程式碼用在多個繼承樹的方法”。簡單的說,mixin讓你不用繼承就可以引入程式碼塊的方法。宣告一個mixin非常的簡單:
mixin Fluttering {
void flutter() {
pring('fluttering');
}
}
複製程式碼
這個mixin可以用在常規的類上面也可以用在抽象類,只需要一個with關鍵字。在野生動物模擬app例子裡,你也許要用在抽象類上了。
mixin Fluttering {
void flutter() {
print('fluttering');
}
}
abstract class Insect {
void crawl() {
print('crawling');
}
}
abstract class AirborneInsect extends Insect with Fluttering {
void buzz() {
print('buzzing annoyingly');
}
}
class Mosquito extends AirborneInsect {
void doMosquitoThing() {
crawl();
flutter();
buzz();
print('sucking blood');
}
}
abstract class Bird with Fluttering {
void chirp() {
print('chirp chirp');
}
}
class Swallow extends Bird {
void doSwallowThing() {
chirp();
flutter();
print('eating a mosquito');
}
}
複製程式碼
也可以在一個類上面使用多個mixin。如果需要在Bird類上用一個chirping mixn的話,就和Fluttering mixin一起用就好。
abstract class Bird with Fluttering, Chirping
複製程式碼
限制Mixin的使用
有的時候你不想讓mixin用在早已存在的類上面,你只是想讓它用在某些特定的類或者其子類上。這通常你的程式碼對早已存在的程式碼有依賴。
在野生動物app這個例子裡,你發現僅僅支援swallow已經不夠了。還有其他種類的鳥比如麻雀或者Blue Jay等。與麻雀不同,很多其他的鳥需要從地裡面啄食,種子啊,蟲子啊的。。。
給Bird抽象類新增方法是不可能的,因為不是所有的鳥都需要啄食。所以,為了避免程式碼冗餘,你可以建立一個叫做Pecking的mixin。
mixin Pecking {
void peck() {
print('pecking');
}
}
複製程式碼
這至少比程式碼榮譽好很多了。但是,也會有人把這個mixin用在Insect類上。這樣使用mixin問題就大了。
當你開始研究一個鳥類的動作的時候,你會發現鳥兒在逐出食物之後就會發出愉悅的鳥鳴。從當前的mixin裡面呼叫chirp方法是不可能的。要改也非常簡單,只要告訴Dart,Pecking mixin只能用在Bird類上面。現在呼叫Bird
類的方法就沒有問題了。
//...
mixin Pecking on Bird {
void peck() {
print('pecking');
chirp();
}
}
class Sparrow extends Bird with Pecking {}
class BlueJay extends Bird with Pecking {}
複製程式碼
結論
Mixin對於繼承體系中避免程式碼的冗餘非常有用處。mixin也可以被約束在只可以用在某些特定的類上面,這讓他們成為了開發的一大利器!