Mixin入門
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 50/110。
Dartでは1つのクラスしか継承(extend)できず、複数のインターフェースを実装(implement)することはできますが、すべてのコードを自分で書かなければならないことを学びました。しかし、関連のない複数のクラス間で実際のコードの実装を共有したい場合はどうすればよいでしょうか?そこで登場するのがミックスイン(mixins)です。
ミックスイン(mixin)は、複数のクラス階層でコードを再利用するための手法です。継承を使用せずに、任意のクラスに「ミックスイン」して新しい機能を提供できる、メソッドとプロパティの束だと考えてください。
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}
void main() {
var duck = Duck();
duck.quack();
duck.swim(); // mixinから
var fish = Fish();
fish.swim(); // 同じ実装、異なるクラス
}withキーワードに注目してください。これはクラスにミックスインを適用する方法です。implementsとは異なり、メソッドを自分で書く必要はありません。ミックスインが実際のコードを提供し、クラスはその機能を自動的に獲得します。
ミックスインは現実的な問題を解決します:Duck と Fish は継承関係にはありませんが、両方とも泳ぐ振る舞いを必要としています。ミックスインを使えば、コードを一度書くだけで、必要な場所ならどこでも共有できます。
チャレンジ
簡単ミックスインを使用して、継承関係のないクラス間で動作を共有する方法を示す楽器システムを構築しましょう。チューニング機能を提供するミックスインを作成し、それを継承関係のない異なる楽器に適用します。
コードを2つのファイルに整理します:
instruments.dart: ここでミックスインと楽器クラスを定義します:Tuning the instrument...と出力するtune()メソッドと、Tuning is perfect!と出力するcheckTuning()メソッドを持つTunableミックスイン。Tunableミックスインを使用するGuitarクラス。コンストラクタを持つString brandプロパティを追加します。[brand] guitar strumming chordsと出力するstrum()メソッドを含めます。- 同じく
Tunableミックスインを使用するPianoクラス。コンストラクタを持つint keysプロパティを追加します。Playing [keys]-key pianoと出力するplay()メソッドを含めます。
main.dart: 楽器ファイルをインポートし、継承関係のない両方の楽器が同じミックスインからどのようにチューニング機能を得るかを実演します:- ブランドが
'Fender'のGuitarを作成します。 88鍵のPianoを作成します。- ギターの場合:
tune()を呼び出し、次にstrum()、最後にcheckTuning()を呼び出します。 - 空行を出力します。
- ピアノの場合:
tune()を呼び出し、次にplay()、最後にcheckTuning()を呼び出します。
- ブランドが
Guitar と Piano は継承関係のない完全に異なる楽器ですが、どちらも Tunable ミックスインから全く同じチューニングメソッドを取得していることに注目してください。チューニングのコードを一度書くだけで、with キーワードを使用して両方のクラスで利用できます。
期待される出力:
Tuning the instrument...
Fender guitar strumming chords
Tuning is perfect!
Tuning the instrument...
Playing 88-key piano
Tuning is perfect!チートシート
ミックスインは、継承を使用せずに、関連のない複数のクラス間でコードを再利用する方法です。これは、任意のクラスに「ミックスイン(混ぜ込む)」ことができるメソッドとプロパティのセットです。
mixinキーワードを使用してミックスインを定義します:
mixin Swimming {
void swim() {
print('Swimming through the water');
}
}withキーワードを使用して、クラスにミックスインを適用します:
class Duck with Swimming {
void quack() {
print('Quack!');
}
}
class Fish with Swimming {
void blowBubbles() {
print('Blub blub');
}
}implementsとは異なり、メソッドの実装を自分自身で書く必要はありません。ミックスインが実際のコードを提供し、クラスはその機能を自動的に獲得します。
DuckとFishは、継承関係になくても、両方ともswim()メソッドを使用できるようになります:
var duck = Duck();
duck.swim(); // ミックスインから
var fish = Fish();
fish.swim(); // 同じ実装、異なるクラス自分で試してみよう
import 'instruments.dart';
void main() {
// TODO: ブランド 'Fender' で Guitar を作成する
// TODO: 88 鍵の Piano を作成する
// TODO: guitar に対して tune()、次に strum()、その次に checkTuning() を呼び出す
// TODO: 空行を出力する
// TODO: piano に対して tune()、次に play()、その次に checkTuning() を呼び出す
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ