@override アノテーション
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 39/110。
@override アノテーションは、親クラスのメソッドを意図的に置き換えていることを Dart(および他の開発者)に伝えるためのベストプラクティスマーカーです。メソッドのオーバーライドはこれなしでも機能しますが、@override を使用することで重要なセーフティネットが追加されます。
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}このアノテーションは、2つの主要な利点を提供します。第一に、意図を明確に文書化します。コードを読む人は誰でも、このメソッドが親クラスに存在することを即座に知ることができます。第二に、親メソッドが実際には存在しない場合、Dartのアナライザーが警告を表示するため、タイポやリファクタリングのミスを早期に発見できます。
@override なしでメソッド名をスペルミスした場合に何が起こるか考えてみましょう:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // タイポ! @override がないと警告が表示されません
print('$name meows');
}
}アノテーションがない場合、Dartはspeek()という名前の新しいメソッドを作成していると想定します。@overrideを付けると、アナライザーは親クラスにそのようなメソッドが存在しないことを即座に指摘します。このシンプルなアノテーションは、後で追跡するのが困難になる可能性のある微妙なバグを防ぎます。
チャレンジ
簡単継承された動作をカスタマイズする際の @override アノテーションの重要性を示すメディアプレーヤーシステムを構築しましょう。それぞれの方法でコンテンツを再生する、異なるメディアタイプを作成します。
コードを2つのファイルに整理します:
media.dart: ここでメディアの階層を定義します:String titleプロパティ、タイトルを受け取るコンストラクタ、およびPlaying: [title]と出力するplay()メソッドを持つMediaクラス。Mediaを継承し、String artistプロパティを追加したSongクラス。@overrideアノテーションを使用し、play()をオーバーライドしてPlaying song: [title] by [artist]と出力するようにします。Mediaを継承し、int durationプロパティ(秒単位)を追加したVideoクラス。@overrideを使用し、play()をオーバーライドして、まずsuper.play()で親クラスのバージョンを呼び出し、次にDuration: [duration] secondsと出力するようにします。
main.dart: メディアファイルをインポートし、オーバーライドされたメソッドを実演します:- タイトルを
'Generic Content'としてMediaオブジェクトを作成し、play()を呼び出します。 - 空行を出力します。
- タイトルを
'Imagine'、アーティストを'John Lennon'としてSongを作成し、play()を呼び出します。 - 空行を出力します。
- タイトルを
'Dart Tutorial'、期間を360としてVideoを作成し、play()を呼び出します。
- タイトルを
@override アノテーションは、あなたの意図を文書化し、エラーを見つけるのに役立ちます。もし誤って play() を plya() と綴り間違えた場合、アノテーションは親クラスにそのようなメソッドが存在しないことを警告してくれます。
期待される出力:
Playing: Generic Content
Playing song: Imagine by John Lennon
Playing: Dart Tutorial
Duration: 360 secondsチートシート
@overrideアノテーションは、親クラスのメソッドを意図的に置き換えるメソッドをマークします。これはオプションですが、安全性と明確さを提供します。
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}@overrideの利点:
- 意図を文書化する - メソッドが親クラスに存在することを示します
- エラーをキャッチする - 親メソッドが存在しない場合にDartのアナライザーが警告を出し、タイポ(打ち間違い)を防ぎます
@overrideがない場合、タイポはエラーを報告する代わりに新しいメソッドを作成してしまいます:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // タイポにより警告なしに新しいメソッドが作成される
print('$name meows');
}
}superを使用して親のバージョンを呼び出すことができます:
@override
void play() {
super.play(); // 最初に親メソッドを呼び出す
print('Additional behavior');
}自分で試してみよう
import 'media.dart';
void main() {
// TODO: タイトルが 'Generic Content' の Media オブジェクトを作成し、play() を呼び出す
// TODO: 空行を出力する
// TODO: タイトルが 'Imagine'、アーティストが 'John Lennon' の Song を作成し、play() を呼び出す
// TODO: 空行を出力する
// TODO: タイトルが 'Dart Tutorial'、duration が 360 の Video を作成し、play() を呼び出す
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ