ポリモーフィズムの基礎
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 57/110。
ポリモーフィズムとは「多くの形態」を意味します。これは、異なるクラスのオブジェクトを共通のインターフェースを通じて扱う能力のことです。親クラスの参照がある場合、それは任意の子クラスのオブジェクトを指すことができ、実際のオブジェクトの型に基づいて適切なメソッドが呼び出されます。
これは、親の型に対して動作するコードを記述しながら、すべての子の型を自動的に正しく処理できるため、非常に強力です。
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // 親の型、子のオブジェクト
myPet.speak(); // 出力: Woof!
myPet = Cat(); // 同じ変数、異なるオブジェクト
myPet.speak(); // 出力: Meow!
}変数myPetはAnimalとして宣言されていますが、実際にはDogまたはCatを保持しています。speak()が呼び出されると、Dartは実行時に実際のオブジェクトの型を確認し、適切なオーバーライドされたメソッドを呼び出します。
これにより、任意のサブクラスで動作する柔軟な関数を記述できるようになります。
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // 各動物がそれぞれの方法で鳴きます
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// 出力: Woof! Meow! Woof!
}この関数は Dog や Cat について知る必要はありません。単に Animal を扱います。これにより、新しい動物の型を追加しても既存の関数を変更する必要がないため、コードの拡張性が向上します。
チャレンジ
簡単ポリモーフィズムの動作を実演する楽器システムを構築しましょう。ベースとなる Instrument クラスといくつかの楽器タイプを作成し、特定のタイプを知らなくても、楽器のコレクションを一緒に演奏させることができる関数を作成します。
コードを2つのファイルに整理します:
instruments.dart: ここで楽器の階層を定義します:String nameプロパティとコンストラクタを持つInstrumentクラス。[name] makes a soundと出力するplay()メソッドを含めます。Instrumentを継承し、play()をオーバーライドして[name] strums melodicallyと出力するGuitarクラス。Instrumentを継承し、play()をオーバーライドして[name] beats rhythmicallyと出力するDrumクラス。Instrumentを継承し、play()をオーバーライドして[name] plays harmoniouslyと出力するPianoクラス。
Concert begins!と出力し、リストを反復処理して各楽器のplay()を呼び出し、最後にConcert ends!と出力する関数performConcert(List<Instrument> instruments)を作成します。main.dart: 楽器ファイルをインポートし、混合バンドを作成してポリモーフィズムを実演します:'Acoustic'という名前のGuitar、'Snare'という名前のDrum、'Grand'という名前のPianoを含むList<Instrument>型のリストを作成します。- このリストを
performConcert()に渡します。
performConcert() が親タイプである Instrument をどのように扱っているか、それにもかかわらず各楽器が独自の方法で演奏されることに注目してください。これがポリモーフィズムです。同じメソッド呼び出しが、実際のオブジェクトのタイプに基づいて異なる動作を生成します。
期待される出力:
Concert begins!
Acoustic strums melodically
Snare beats rhythmically
Grand plays harmoniously
Concert ends!チートシート
ポリモーフィズム(多態性)は「多くの形態」を意味し、異なるクラスのオブジェクトを共通のインターフェースを通じて扱うことを可能にします。親クラスの参照は任意の子クラスのオブジェクトを指すことができ、実行時の実際のオブジェクト型に基づいて適切なメソッドが呼び出されます。
ポリモーフィズムの基本的な例:
class Animal {
void speak() => print('Some sound');
}
class Dog extends Animal {
@override
void speak() => print('Woof!');
}
class Cat extends Animal {
@override
void speak() => print('Meow!');
}
void main() {
Animal myPet = Dog(); // 親の型、子のオブジェクト
myPet.speak(); // 出力: Woof!
myPet = Cat(); // 同じ変数、異なるオブジェクト
myPet.speak(); // 出力: Meow!
}ポリモーフィズムにより、任意のサブクラスで動作する柔軟な関数が可能になります:
void makeAllSpeak(List<Animal> animals) {
for (var animal in animals) {
animal.speak(); // 各動物がそれぞれの方法で鳴きます
}
}
void main() {
var pets = [Dog(), Cat(), Dog()];
makeAllSpeak(pets);
// 出力: Woof! Meow! Woof!
}この関数は、DogやCatのような特定のクラスを知る必要がなく、親の型であるAnimalで動作します。これによりコードの拡張性が高まり、新しい型を追加しても既存の関数を変更する必要がなくなります。
自分で試してみよう
import 'instruments.dart';
void main() {
// TODO: 次を含む List<Instrument> を作成してください:
// - 'Acoustic' という名前の Guitar
// - 'Snare' という名前の Drum
// - 'Grand' という名前の Piano
// TODO: 作成した楽器のリストを引数にして performConcert() を呼び出してください
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ