在Java語言中,子類只能繼承extends單個父類,實現implements多個介面(即單繼承和多實現)。在Dart語言中,所有類型均是Object子類,它們也是單繼承和多實現,但Dart中有個Mixin的高級特性,它可以做到更多的代碼復用(單繼承、多實現、多Mixin代碼復用)…… ...
Dart官網文檔:https://dart.dev/language/mixins
重要說明:本博客基於Dart官網文檔,但並不是簡單的對官網進行翻譯,在覆蓋核心功能情況下,我會根據個人研發經驗,加入自己的一些擴展問題和場景驗證。
Mixin目的和使用方法(with)
官網文檔:Mixins are a way of defining code that can be reused in multiple class hierarchies. They are intended to provide member implementations en masse.
大概意思:Mixin是一種定義可在多個類層次結構中復用代碼的方法。Mixin的目標是為這些類提供一批成員實現(類屬性+類方法)。
總結起來:使用Mixin可以讓代碼被其他類所使用(包括屬性和方法)。
使用方法:通過mixin
關鍵字定義一個Mixin類;通過with
關鍵字,一個類可以同時復用多個mixin成員實現。
代碼樣例:如下代碼,ClassA同時擁有了MixinOne+MixinTwo+MixinThree這3個Mixin的所有成員屬性和類方法(感覺有的像多繼承?)。
mixin MixinOne {
......
}
mixin MixinTwo {
......
}
mixin MixinThree {
......
}
class ClassA extends SupperClass with MixinOne, MixinTwo, MixinThree {
......
}
Mixin的使用有哪些約束呢?
- Mixin不能繼承其他Mixin或者抽象類。
- Mixin不能有構造方法,也就是Mixin不能被實例化。
Mixin限定/繼承其他類型(on)
為了更好的維護Mixin這些可復用的代碼,我們有時需要嚴格限定使用Mixin的類型,通過on
關鍵字達到目的。
代碼樣例:如下代碼,MixinFine通過on
關鍵字限定使用它的類型是SupperClass,凡是使用MixinFine的類,必須extends繼承SupperClass這個Mixin限定的類型。
class SupperClass {
......
}
mixin MixinFine on SupperClass {
......
}
class ClassFine extends SupperClass with MixinFine {
......
}
mixin class介紹和使用(類+Mixin)
我們通過mixin
定義一個Mixin,通過class
定義一個類;那麼通過mixin class
就可以定義一個mixin和一個類,它們具有相同的名字和相同的類型。
Mixin和類的所有約束,在mixin class同時生效,包括如下:
- Mixin不支持extends繼承其他類和with復用其他Mixin,因此mixin class也不能有extends繼承其他類和with復用其他Mixin
- 普通類不支持通過on關鍵字限定可使用類型,因此mixin class也不支持on關鍵字(但是我們可以通過abstract達到此目的)。
代碼樣例:如下代碼,mixin class
可通過with
關鍵字當成Mixin被使用,也可通過extends
關鍵字當成類被繼承使用。
abstract mixin class Musician {
// 含有abstract方法,使用它的類必須實現本方法
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
class Virtuoso with Musician {
// with關鍵字,Musician作為一個Mixin被使用
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
class Novice extends Musician {
// extends關鍵字,Musician作為一個類被繼承
void playInstrument(String instrumentName) {
print('Plays the $instrumentName poorly');
}
}
擴展問題:Mixin如何解決二義性?(覆蓋)
通過上面的說明,一個類可以使用多個Mixin的實現,那麼有個問題:他們是如何解決二義性的呢?
樣例說明:如下代碼,我們有2個Mixin,他們的屬性和方法都是相同,同時使用他們時,最終的屬性和方法是哪個Mixin的呢?
mixin MixinA {
String className = "MixinA";
void log() {
print(className);
}
}
mixin MixinB {
String className = "MixinB";
void log() {
print(className);
}
}
class ClassMixinAB with MixinA, MixinB {
}
class ClassMixinBA with MixinB, MixinA {
}
void main() {
ClassMixinAB mixinAB = ClassMixinAB();
mixinAB.log();
// 結果:MixinB
ClassMixinBA mixinBA = ClassMixinBA();
mixinBA.log();
// 結果:MixinA
}
通過上面2個代碼樣例,基本可以判斷:Mixin解決二義性的方式非常粗暴,後面Mixin覆蓋前面Mixin!!!
Mixin使用場景:列印State生命周期日誌
Mixin通過代碼復用,可以應用在很多的應用場景。下麵代碼樣例,可以在Flutter組件生命周期邏輯執行之後,列印響應的日誌。
樣例代碼:LogStateMixin通過on
關鍵字限定/繼承了State類型,內部的方法,均通過super代理了State的內容,同時列印相應的日誌。
mixin LogStateMixin<T extends StatefulWidget> on State<T> {
@override
void initState() {
super.initState();
print("====initState====");
}
@override
void dispose() {
super.dispose();
print("====dispose====");
}
// 其他方法......
}
在凡是想要監聽組件的生命周期的組件中,可以使用上面的Mixin即可,無其他侵入代碼,特別適合在Flutter應用研發過程中,通過日誌觀測組件的生命周期:
class _MinePageState extends State<MinePage> with LogStateMixin<MinePage>
// 我的頁面邏輯,無需關心日誌....
}
這樣在頁面初始化、銷毀的時候,列印響應的日誌。
我的本博客原地址:https://ntopic.cn/p/2023093001
本文作者:奔跑的蝸牛,轉載請註明原文鏈接:https://ntopic.cn