メインコンテンツにスキップ

Mixin

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

Mixinを使用するには、`with`キーワードの後に1つ以上のMixin名を続けます。次の例では、Mixinを使用する(または、Mixinのサブクラスである)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`宣言を使用します。Mixinクラスの両方を定義する必要があるまれなケースでは、`mixin class宣言`を使用できます。

MixinとMixinクラスは`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');
    }
  }
}

Mixinが自身で呼び出せるメンバーを指定する

#

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

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

Mixinで抽象メンバーを定義する

#

Mixinで抽象メソッドを宣言すると、Mixinを使用するすべての型が、その動作が依存する抽象メソッドを定義するように強制されます。

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

Mixinのサブクラスで状態にアクセスする

#

抽象メンバーを宣言することは、Mixinで抽象として定義されたgetterを呼び出すことにより、Mixinのサブクラスの状態にアクセスすることも可能にします。

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

インターフェースを実装する

#

Mixinを抽象として宣言することと同様に、Mixinに`implements`句を付けたものの、実際にはインターフェースを実装しない場合でも、Mixinのすべてのメンバー依存関係が定義されていることを保証できます。

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`呼び出しが解決される型を定義するために存在します。したがって、Mixin内に`super`呼び出しが必要な場合にのみ使用してください。

`on`句は、Mixinを使用するすべてのクラスが`on`句の型のサブクラスになることを強制します。Mixinがスーパークラスのメンバーに依存している場合、これはMixinが使用される場所でそれらのメンバーが利用可能であることを保証します。

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` Mixinを使用できます。`SingerDancer`は`Musician`を拡張しているため、`SingerDancer`は`MusicalPerformer`をMixinできます。

classmixin、またはmixin class

#

`mixin`宣言はMixinを定義します。`class`宣言はクラスを定義します。`mixin class`宣言は、通常のクラスとしてもMixinとしても使用できるクラスを、同じ名前と型で定義します。

dart
mixin class Musician {
  // ...
}

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

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

クラスまたはMixinに適用される制限は、Mixinクラスにも適用されます。

  • Mixinは`extends`または`with`句を持つことができないため、`mixin class`も同様です。
  • クラスは`on`句を持つことができないため、`mixin class`も同様です。