目次

ミックスイン

ミックスインは、複数のクラス階層で再利用できるコードを定義する方法です。それらは、まとめてメンバー実装を提供することを目的としています。

ミックスインを使用するには、`with`キーワードの後に1つ以上のミックスイン名を続けます。次の例は、ミックスインを使用する(または、ミックスインのサブクラスである)2つのクラスを示しています。

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');
    }
  }
}

ミックスインが自身で呼び出すことができるメンバーを指定する

#

ミックスインは、メソッドを呼び出したりフィールドにアクセスしたりできることに依存することがありますが、それらのメンバー selbst定義することはできません(ミックスインはコンストラクタパラメータを使用して独自のフィールドをインスタンス化できないためです)。

以下のセクションでは、ミックスインのサブクラスがミックスインの動作が依存するメンバーを定義することを保証するためのさまざまな戦略について説明します。

ミックスインで抽象メンバーを定義する

#

ミックスインで抽象メソッドを宣言すると、ミックスインを使用するすべての型は、その動作が依存する抽象メソッドを定義する必要があります。

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

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

class Virtuoso with Musician { 
  void playInstrument(String instrumentName) { // Subclass must define.
    print('Plays the $instrumentName beautifully');
  }  
}

ミックスインのサブクラスの状態にアクセスする

#

抽象メンバーを宣言することで、ミックスインで抽象として定義されているゲッターを呼び出すことにより、ミックスインのサブクラスの状態にアクセスすることもできます。

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;

  int get hashCode => name.hashCode;
  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 {
  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`をミックスインできます。

`class`、`mixin`、または`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
  // ...
}

クラスまたはミックスインに適用される制限は、ミックスインクラスにも適用されます。

  • ミックスインは`extends`または`with`句を持つことができないため、`mixin class`も持つことができません。
  • クラスは`on`句を持つことができないため、`mixin class`も持つことができません。