跳到主要內容

混入

混入是一種定義程式碼的方式,這些程式碼可以在多個類層次結構中複用。它們旨在大量提供成員實現。

要使用混入,請使用 with 關鍵字,後跟一個或多個混入名稱。以下示例展示了使用(或繼承自)混入的兩個類

dart
class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}

要定義混入,請使用 mixin 宣告。在極少數情況下,當你需要同時定義混入和類時,可以使用 mixin class 宣告

混入和混入類不能有 extends 子句,並且不得宣告任何生成式建構函式。

例如

dart
mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

指定混入可以呼叫的自身成員

#

有時混入依賴於能夠呼叫方法或訪問欄位,但不能自行定義這些成員(因為混入不能使用建構函式引數來例項化自己的欄位)。

以下各節介紹了確保混入的任何子類定義混入行為所依賴的任何成員的不同策略。

在混入中定義抽象成員

#

在混入中宣告抽象方法會強制使用該混入的任何型別定義其行為所依賴的抽象方法。

dart
mixin Musician {
  void playInstrument(String instrumentName); // Abstract method.

  void playPiano() {
    playInstrument('Piano');
  }
  void playFlute() {
    playInstrument('Flute');
  }
}

class Virtuoso with Musician { 

  @override
  void playInstrument(String instrumentName) { // Subclass must define.
    print('Plays the $instrumentName beautifully');
  }  
}

在混入的子類中訪問狀態

#

宣告抽象成員還允許你透過呼叫在混入中定義為抽象的 getter 來訪問混入子類上的狀態

dart
/// Can be applied to any type with a [name] property and provides an
/// implementation of [hashCode] and operator `==` in terms of it.
mixin NameIdentity {
  String get name;

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator ==(other) => other is NameIdentity && name == other.name;
}

class Person with NameIdentity {
  final String name;

  Person(this.name);
}

實現介面

#

與將混入宣告為抽象類似,在混入上新增 implements 子句但未實際實現介面,也將確保為混入定義所有成員依賴項。

dart
abstract interface class Tuner {
  void tuneInstrument();
}

mixin Guitarist implements Tuner {
  void playSong() {
    tuneInstrument();

    print('Strums guitar majestically.');
  }
}

class PunkRocker with Guitarist {

  @override
  void tuneInstrument() {
    print("Don't bother, being out of tune is punk rock.");
  }
}

使用 on 子句宣告超類

#

on 子句用於定義 super 呼叫所解析的型別。因此,你只應在混入內部需要進行 super 呼叫時使用它。

on 子句強制使用混入的任何類也是 on 子句中型別的子類。如果混入依賴於超類中的成員,這可以確保在使用混入的地方這些成員是可用的

dart
class Musician {
  musicianMethod() {
    print('Playing music!');
  }
}

mixin MusicalPerformer on Musician {
  performerMethod() {
    print('Performing music!');
    super.musicianMethod();
  }
}

class SingerDancer extends Musician with MusicalPerformer { }

main() {
  SingerDancer().performerMethod();
}

在此示例中,只有擴充套件或實現 Musician 類的類才能使用混入 MusicalPerformer。因為 SingerDancer 擴充套件了 Musician,所以 SingerDancer 可以混入 MusicalPerformer

classmixin 還是 mixin class

#

mixin 宣告定義一個混入。class 宣告定義一個mixin class 宣告定義一個類,該類可以用作普通類,也可以用作混入,具有相同的名稱和型別。

dart
mixin class Musician {
  // ...
}

class Novice with Musician { // Use Musician as a mixin
  // ...
}

class Novice extends Musician { // Use Musician as a class
  // ...
}

適用於類或混入的任何限制也適用於混入類

  • 混入不能有 extendswith 子句,因此 mixin class 也不能有。
  • 類不能有 on 子句,因此 mixin class 也不能有。