動態

詳情 返回 返回

Flutter/Dart第05天:Dart特殊特性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的使用有哪些約束呢?

  1. Mixin不能繼承其他Mixin或者抽象類。
  2. 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同時生效,包括如下:

  1. Mixin不支持extends繼承其他類和with複用其他Mixin,因此mixin class也不能有extends繼承其他類和with複用其他Mixin
  2. 普通類不支持通過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


Add a new 評論

Some HTML is okay.