Menu
Coddy logo textTech

インターフェースによるポリモーフィズム

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 58/110。

前のレッスンでは、継承によるポリモーフィズム(親クラスの型を使用して子オブジェクトを操作すること)について学びました。しかし、ポリモーフィズムはインターフェースを通じても機能し、このアプローチは多くの場合、より柔軟です。

クラスが同じインターフェースを実装している場合、継承関係がなくても、それらをポリモーフィックに扱うことができます:

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

class Receipt implements Printable {
  @override
  void printDetails() => print('Receipt for purchase');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report(), Receipt()];
  printAll(documents);
}

InvoiceReport、および Receipt は完全に無関係なクラスであり、親クラスを共有していません。しかし、これらはすべて Printable を実装しているため、これらを同じリストに格納し、それぞれに対して printDetails() を呼び出すことができます。

これは、継承階層を強制することなく振る舞いのコントラクトを定義できるため、非常に強力です。何を継承しているかに関わらず、どのクラスでもインターフェースを実装できます。既存のコードを修正することなく、新しい印刷可能な型を追加できるため、コードのモジュール性が高まります。単にインターフェースを実装するだけです。

challenge icon

チャレンジ

簡単

インターフェースを通じてポリモーフィズムを実証するメディアプレーヤーシステムを構築しましょう。「再生可能」であることの意味を定義するインターフェースを作成し、継承関係がないにもかかわらず、このコントラクトを満たすすべての無関係なメディアタイプをいくつか実装します。これにより、それらを一律に扱うことができるようになります。

コードを2つのファイルに整理します:

  • media.dart: ここでインターフェースとメディアクラスを定義します:
    • 2つの抽象メソッド play()String getMediaType() を持つ抽象クラス Playable
    • Playable を実装する Song クラス。String titleString artist を持つ必要があります。その play() メソッドは Playing song: [title] by [artist] を出力し、getMediaType()'Audio' を返します。
    • Playable を実装する Video クラス。String titleint duration(分単位)を持つ必要があります。その play() メソッドは Playing video: [title] ([duration] min) を出力し、getMediaType()'Video' を返します。
    • Playable を実装する Podcast クラス。String titleint episode を持つ必要があります。その play() メソッドは Playing podcast: [title] - Episode [episode] を出力し、getMediaType()'Podcast' を返します。
    また、リストを反復処理し、各アイテムに対して [Media Type]: を出力した後にそのアイテムの play() を呼び出す関数 playAll(List<Playable> playlist) を作成します。
  • main.dart: メディアファイルをインポートし、インターフェースベースのポリモーフィズムを実証します:
    • タイトルが 'Imagine' でアーティストが 'John Lennon'Song、タイトルが 'Dart Tutorial' で再生時間が 15Video、タイトルが 'Tech Talk' でエピソードが 42Podcast を含む List<Playable> を作成します。
    • このリストを playAll() に渡します。

SongVideoPodcast が親クラスを共有していないことに注目してください。これらは完全に無関係な型です。しかし、すべてが Playable を実装しているため、同じリストに保存し、インターフェースを通じて一律に扱うことができます。

期待される出力:

Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42

チートシート

ポリモーフィズムはインターフェースを通じて機能し、継承関係のない無関係なクラスを統一的に扱うことを可能にします。

同じインターフェースを実装するクラスは、ポリモーフィックに使用できます:

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report()];
  printAll(documents);
}

インターフェースベースのポリモーフィズムにより、以下のことが可能になります:

  • 継承階層を強制することなく、振る舞いの契約を定義する
  • 無関係な型を同じコレクションに格納する
  • 既存のコードを修正することなく、新しい型を追加する
  • コードをよりモジュール化し、柔軟にする

自分で試してみよう

import 'media.dart';

void main() {
  // TODO: 以下の内容を含む List<Playable> を作成してください:
  // - タイトルが 'Imagine'、アーティストが 'John Lennon' の Song
  // - タイトルが 'Dart Tutorial'、再生時間が 15 の Video
  // - タイトルが 'Tech Talk'、エピソード番号が 42 の Podcast
  
  // TODO: そのリストを playAll() に渡してください
}
quiz icon腕試し

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

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