Menu
Coddy logo textTech

実装 vs 継承

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

extendsimplements の両方を理解したところで、それぞれをいつ使うべきかを明確にしましょう。

動作を継承したいときは extends を使用します。サブクラスは親クラスのコードをすべて無料で取得し、それを基に構築できます。

class Animal {
  void breathe() {
    print('Breathing...');
  }
}

class Dog extends Animal {
  void bark() {
    print('Woof!');
  }
}

void main() {
  var dog = Dog();
  dog.breathe();  // 継承された - 自動的に動作する
  dog.bark();
}

コードを継承せずに構造を保証したい場合は、implements を使用します。すべてのメソッドを自分で記述する必要があります。

class Robot implements Animal {
  @override
  void breathe() {
    print('Ventilating circuits...');  // 完全にカスタムな実装
  }
}

重要な違い:extends は「これはこの型の一種です」と示すのに対し、implements は「これはこれが行うことを実行できます」と示します。DogAnimal であり、同じように呼吸します。Robot は動物ではありませんが、独自のロジックで同じ契約を満たすことができます。

覚えておいてください。拡張できるクラスは1つだけですが、多くのインターフェースを実装できます。真の継承関係にはextendsを選び、柔軟性が必要な場合や実装の詳細を共有せずに契約を適用したい場合にはimplementsを選びます。

challenge icon

チャレンジ

簡単

extendsimplements のどちらを使うべきかを示す worker システムを構築しましょう。まず基本となる worker クラスを作成し、2つのアプローチを示します。一方は本当に worker 「is a」であり、behavior を継承するクラス、もう一方は worker が行うことを「can do」できるだけで、完全にカスタムされたロジックを持つクラスです。

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

  • worker.dart: ここで worker の階層を定義します。
    • String name プロパティとコンストラクターを持つ Worker クラス。[name] is working... を出力する work() メソッドと、[name] takes a coffee break を出力する takeBreak() メソッドを含めます。
    • Workerextends する OfficeWorker クラス。String department プロパティを追加します。work() をオーバーライドして [name] is typing reports in [department] を出力しますが、継承した takeBreak() の behavior は維持します。
    • Workerimplements する RobotWorker クラス。String model プロパティを追加します。ロボットは本当の worker ではありませんが、worker が行うことを実行できるため、完全にカスタムされた implementation を提供します。work()Robot [model] is assembling parts を出力し、takeBreak()Robot [model] is recharging を出力するようにします。
  • main.dart: worker ファイルを import し、両方のアプローチを示します。
    • 'Alice' という名前の OfficeWorker'Marketing' department に作成します。
    • モデルが 'RX-7'RobotWorker を作成します。
    • office worker について、work() を呼び出してから takeBreak() を呼び出します。
    • empty line を出力します。
    • robot worker について、work() を呼び出してから takeBreak() を呼び出します。

OfficeWorkerWorker を extends しているため、takeBreak() を automatically 継承することに注目してください。つまり、本当に worker 「is a」です。一方、RobotWorker は interface を implements するだけなので、すべてについて独自の implementation を提供する must があります。worker が行うことを「can do」しますが、独自のロボットらしい方法で実行します。

Expected output:

Alice is typing reports in Marketing
Alice takes a coffee break

Robot RX-7 is assembling parts
Robot RX-7 is recharging

自分で試してみよう

import 'worker.dart';

void main() {
  // TODO: 'Marketing' 部門に 'Alice' という名前の OfficeWorker を作成する
  
  // TODO: モデル 'RX-7' の RobotWorker を作成する
  
  // TODO: オフィスワーカーに対して work() を呼び出してから takeBreak() を呼び出す
  
  // TODO: 空行を出力する
  
  // TODO: ロボットワーカーに対して work() を呼び出してから takeBreak() を呼び出す
}
quiz icon腕試し

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

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

自分で練習してみよう: Dartオンラインコンパイラ