Menu
Coddy logo textTech

ポリモーフィズムの基礎

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!
}

変数myPetAnimalとして宣言されていますが、実際には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!
}

この関数は DogCat について知る必要はありません。単に Animal を扱います。これにより、新しい動物の型を追加しても既存の関数を変更する必要がないため、コードの拡張性が向上します。

challenge icon

チャレンジ

簡単

ポリモーフィズムの動作を実演する楽器システムを構築しましょう。ベースとなる 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!
}

この関数は、DogCatのような特定のクラスを知る必要がなく、親の型であるAnimalで動作します。これによりコードの拡張性が高まり、新しい型を追加しても既存の関数を変更する必要がなくなります。

自分で試してみよう

import 'instruments.dart';

void main() {
  // TODO: 次を含む List<Instrument> を作成してください:
  // - 'Acoustic' という名前の Guitar
  // - 'Snare' という名前の Drum
  // - 'Grand' という名前の Piano
  
  
  // TODO: 作成した楽器のリストを引数にして performConcert() を呼び出してください
  
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン