「 Flutter のコードの中で出てくる extends ってなんだろう? 」
本記事ではそんな疑問にお答えします。
Flutter / Dart での extends の役割について解説します。
コードリーディングの役に立つ知識となっています。
丁寧に解説しますので、ぜひ読んでみてください!
extends って何?
extends の役割
extendsはクラスの拡張を表すキーワードです。
あるクラスに対し、そのクラスの機能を持ちつつ、追加の機能を持つサブクラスを 作成するのに用います。
クラスとは何かについては、以下の本にもまとまっております。
本記事ではextendsを『拡張』と訳します。
記事によっては『継承』と訳しているものもあります。
本記事では英和辞書の訳を正とし『拡張』と表記します。
具体例
拡張クラスの作成方法から、その特徴まで具体例を用いて解説します。
拡張クラスの作成
Monkeyというクラスを作成してみます。
class Monkey{
const Monkey({required this.name});
final String name;
void move(){
print('move!');
}
void cry(){
print('screech!');
}
}
nameというフィールドを持ち、
moveというメソッドと、cryというメソッドを持つクラスです。
このクラスを拡張したクラスとして、Humanというクラスを以下のように作成します。
class Human extends Monkey{
const Human({required super.name});
void sayTheName(){
print(name);
}
}
extends の後にMonkeyと続けることで、Monkeyクラスを拡張したクラスとして定義できます。
ここで、Monkey クラスでnameというフィールドは必須です。
拡張したクラスのHumanクラスでは
元のMonkeyクラス のnameフィールドに値を設定する必要があります。
設定するための一つの方法がコンストラクタの引数として同様に受け取る方法です。
拡張していない場合はrequired this.nameと書くところを、
required super.nameと書くことで、
元のMonkeyクラス のnameフィールドに値を設定することができます。
HumanクラスのsayTheNameメソッドは、nameというフィールドを参照しています。
Humanクラスでnameフィールドは定義していないため、一見エラーになりそうですが、
拡張元のMonkeyクラスで定義されているため、エラーとならなりません。
以上が、拡張クラスの作り方と解説になります。
メソッドの実行
上で定義したHumanクラスを使って、以下のコードを実行してみましょう。
void main(){
print('Human'); // 実行結果: Human
final human = Human(name: 'Aoi');
human.move(); // 実行結果: move!
}
上のHumanクラスのコードの中にはmoveというメソッドは定義されていません。
ですが、human.move();でエラーは発生せず、move! という実行結果が返ってきます。
これは拡張することにより、HumanクラスがMonkeyクラスの機能を持つ
(Monkeyクラスで定義したmoveというメソッドを使える)
ためです。
メソッドの上書き
Humanクラスを以下のように修正し、メソッドを追加しましょう。
class Human extends Monkey{
const Human({required super.name});
@override
void cry(){
print('uwaaaaaaah');
}
void sayTheName(){
print(name);
}
}
Monkeyで定義していたcryメソッドをもう一度定義し直しています。
クラスの拡張では、元のクラス(Monkey)のメソッドをサブクラス(Humanクラス)にて、
上書きすることができます。
これをオーバーライドする、といいます。
以下のように、Monkeyクラスのcryメソッドと、
Humanクラスのcryメソッドの実行結果を比較してみましょう。
void main(){
print('Monkey'); // 実行結果: Monkey
final monkey = Monkey(name:'George');
monkey.cry(); // 実行結果: screech!
print('Human'); // 実行結果: Human
final human = Human(name: 'Aoi');
human.cry(); // 実行結果: uwaaaaaaah
}
上書きが上手くいっていることが確認できます。
以上が上書き(オーバーライド)の解説でした。
以下のDartPadで今回紹介したサンプルを実際に実行してみて学ぶことができます。 是非参考にしてみてください。
Flutterでの例
flutter create で作られるカウンターアプリで、このようなクラスがあります。
class MyApp extends StatelessWidget {
const MyApp({super.key});
// コメント省略
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// コメント省略
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
StatelessWidgetクラスをextendsしているので、
このMyAppというクラスは、StatelessWidgetを拡張したクラス、となります。
これにより、MyAppというクラスはStatelessWidgetの機能を持ち、
ウィジェットとしてFlutterのUIを構築する機能を持つわけです。
また上で記載したオーバーライドも利用して、buildメソッドを上書きしていることがわかります。
以上が、Flutterでの例でした。
まとめ
本記事では、Flutter / Dart での extends の役割について解説しました。
いかがだったでしょうか。
上手く使えば、メソッドの共用化ができるテクニックとなっています。 またFlutter 等の内部コードを読む際に欠かせない知識でもあります。
ちょっと難しいテーマでしたが、 ぜひ本記事を参考にして、理解を深めてみてください!
本記事があなたのアプリ開発の一助となれば幸いです。
Flutterを一緒に学んでみませんか? Flutter エンジニアに特化した学習コミュニティ、Flutter大学への入会は、 以下の画像リンクから。
参考
編集後記(2022/10/14)
extendsについての記事でした。
記事途中の注釈でも書きましたが、extendsの訳を『拡張』と訳すか、
『継承』と訳すかは悩みどころでした。
なので、記事を書くにあたってのTwitterアンケートもやってみました。
(2022年10月14日20:00現在投票受付中です。 ぜひあなたのご意見もお聞かせください。)
記事を書いてる現在だと、いい勝負となっています。
個人的には辞書的に正しい訳の『拡張』が好みですが、 『継承』も実装でやりたいこととしては間違えてはいないし、 おそらく『継承』といったほうが他の言語を触っている人からすると、 理解しやすいのかな、とも思います。
これを『継承』と訳した大元をみつけて、 なぜそう訳したのか確認してみたいです。
ご存じの方いれば、ぜひTwitter等でご教授いただければと思います。
週刊Flutter大学では、Flutterに関する技術記事、Flutter大学についての紹介記事を投稿していきます。 記事の更新情報はFlutter大学Twitterにて告知します。 ぜひぜひフォローをお願いいたします。