メソッドのオーバーライド
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 38/110。
メソッドのオーバーライドは、親クラスに既に存在するメソッドに対して、子クラスが独自の定義(実装)を提供したときに発生します。これにより、サブクラスは同じメソッドシグネチャを維持しながら、継承された動作をカスタマイズすることができます。
子クラスで、親クラスと同じ名前および引数を持つメソッドを定義すると、子クラスのバージョンが優先されます。
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
void speak() {
print('$name barks: Woof!');
}
}
void main() {
var animal = Animal('Generic');
var dog = Dog('Buddy');
animal.speak(); // Generic makes a sound
dog.speak(); // Buddy barks: Woof!
}Dog インスタンスで speak() を呼び出すと、Dart は Animal のバージョンではなく、Dog のバージョンを実行します。子クラスが親クラスのメソッドを オーバーライド したことになります。
オーバーライドを super と組み合わせることで、親の振る舞いを置き換えるのではなく、拡張することもできます:
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // 最初に親のメソッドを呼び出す
print('$name also purrs');
}
}このパターンにより、既存の機能を拡張することができます。重要なルールはシンプルです。子クラスで同じメソッド名とパラメータを定義すると、その子クラスのインスタンスから呼び出された際に、親クラスの実装が上書きされます。
チャレンジ
簡単子クラスが親クラスのメソッドをオーバーライドして動作をカスタマイズする方法を示す通知システムを構築しましょう。それぞれ独自の方法でメッセージを配信する、異なる通知タイプを作成します。
コードを2つのファイルに整理します:
notification.dart: ここで通知の階層を定義します:String titleとString messageを持つNotificationクラス(親クラス)。両方の値を受け取るコンストラクタと、Notification: [title] - [message]と出力するsend()メソッドを含めます。Notificationを継承し、String recipientプロパティを追加するEmailNotificationクラス。send()メソッドをオーバーライドして、Sending email to [recipient]: [title] - [message]と出力するようにします。Notificationを継承し、String deviceIdプロパティを追加するPushNotificationクラス。send()メソッドをオーバーライドして、まずsuperを使用して親のsend()を呼び出し、次にPushed to device: [deviceId]を次の行に出力するようにします。
main.dart: 通知ファイルをインポートし、メソッドのオーバーライドが動作する様子を確認します:- タイトルが
'Alert'、メッセージが'System update available'のベースとなるNotificationを作成します。 - その
send()メソッドを呼び出します。 - 空行を出力します。
- タイトルが
'Welcome'、メッセージが'Thanks for signing up!'、受信者が'user@example.com'のEmailNotificationを作成します。 - その
send()メソッドを呼び出します。 - 空行を出力します。
- タイトルが
'Reminder'、メッセージが'Meeting in 10 minutes'、deviceId が'DEVICE-001'のPushNotificationを作成します。 - その
send()メソッドを呼び出します。
- タイトルが
EmailNotification が親の動作を完全に置き換えるのに対し、PushNotification は最初に super.send() を呼び出すことで動作を拡張している点に注目してください。どちらのアプローチも、ニーズに応じてメソッドをオーバーライドする有効な方法です。
期待される出力:
Notification: Alert - System update available
Sending email to user@example.com: Welcome - Thanks for signing up!
Notification: Reminder - Meeting in 10 minutes
Pushed to device: DEVICE-001チートシート
メソッドのオーバーライドは、子クラスが親クラスに既に存在するメソッドに対して独自の定義を提供したときに発生します。子クラスのインスタンスで呼び出されると、親クラスのメソッドの代わりに子クラスのメソッドが実行されます。
メソッドをオーバーライドするには、子クラスで同じ名前とパラメータを使用して定義します。
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
void speak() {
print('$name barks: Woof!');
}
}
void main() {
var animal = Animal('Generic');
var dog = Dog('Buddy');
animal.speak(); // Generic makes a sound
dog.speak(); // Buddy barks: Woof!
}super を使用して親クラスのメソッドを呼び出すことで、動作を完全に置き換えるのではなく、拡張することができます。
class Cat extends Animal {
Cat(String name) : super(name);
void speak() {
super.speak(); // 最初に親クラスのバージョンを呼び出す
print('$name also purrs');
}
}自分で試してみよう
import 'notification.dart';
void main() {
// TODO: title が 'Alert'、message が 'System update available' のベースとなる Notification を作成してください
// その send() メソッドを呼び出します
// TODO: 空行を出力してください
// TODO: 以下の内容で EmailNotification を作成してください:
// - title: 'Welcome'
// - message: 'Thanks for signing up!'
// - recipient: 'user@example.com'
// その send() メソッドを呼び出します
// TODO: 空行を出力してください
// TODO: 以下の内容で PushNotification を作成してください:
// - title: 'Reminder'
// - message: 'Meeting in 10 minutes'
// - deviceId: 'DEVICE-001'
// その send() メソッドを呼び出します
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ