抽象クラス
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 43/110。
抽象クラスは、直接インスタンス化できないクラスです。他のクラスの設計図として機能し、サブクラスが従わなければならない共通の構造を定義します。abstract キーワードを使用して作成します。
abstract class Shape {
String color;
Shape(this.color);
void describe() {
print('A $color shape');
}
}
class Circle extends Shape {
double radius;
Circle(String color, this.radius) : super(color);
}
void main() {
// Shape s = Shape('red'); // エラー!抽象クラスはインスタンス化できません
var circle = Circle('blue', 5.0);
circle.describe(); // A blue shape
}抽象クラスは、それ自体では存在するには一般的すぎる概念を扱う場合に便利です。「Shape(図形)」は概念ですが、それが円、長方形、あるいは三角形であるかを知らなければ、図形を描くことはできません。抽象クラスはすべての図形に共通する要素を定義し、具体的なサブクラスが詳細な内容を提供します。
抽象クラスは、依然として実装を持つ通常のメソッド(describe() など)やコンストラクタを持つことができる点に注意してください。サブクラスは、通常の継承と同じようにこれらを継承します。主な違いは、単に抽象クラス自体のインスタンスを作成できないという点です。つまり、具体的なサブクラスを使用する必要があります。
チャレンジ
簡単抽象クラスがより具体的な型の設計図としてどのように機能するかを示す、乗り物システムを構築しましょう。すべての乗り物に共通する要素を定義する抽象基底クラスを作成し、それを具体的な乗り物の型で拡張します。
コードを2つのファイルに整理します:
vehicle.dart: ここで乗り物の階層を定義します:String brandとint yearプロパティを持つabstract class Vehicle。両方の値を受け取るコンストラクタと、[brand] ([year])を出力するdisplayInfo()メソッドを含めます。Vehicleを継承し、int doorsプロパティを追加するCarクラス。Beep beep!を出力するhonk()メソッドを含めます。Vehicleを継承し、bool hasSidecarプロパティを追加するMotorcycleクラス。Vroom!を出力するrevEngine()メソッドを含めます。
main.dart: 乗り物ファイルをインポートし、抽象クラスがどのように機能するかを示します:- ブランド
'Toyota'、年2022、ドア数4のCarを作成します。 - その
displayInfo()メソッド(Vehicleから継承)を呼び出します。 Doors: [doors]を出力します。- その
honk()メソッドを呼び出します。 - 空行を出力します。
- ブランド
'Harley'、年2021、hasSidecarfalseのMotorcycleを作成します。 - その
displayInfo()メソッドを呼び出します。 Has sidecar: [hasSidecar]を出力します。- その
revEngine()メソッドを呼び出します。
- ブランド
Vehicle は抽象クラスであるため、直接インスタンスを作成することはできません。具体的なサブクラスのいずれかを使用する必要があります。Car と Motorcycle はどちらも、抽象親クラスから displayInfo() メソッドを継承します。
期待される出力:
Toyota (2022)
Doors: 4
Beep beep!
Harley (2021)
Has sidecar: false
Vroom!チートシート
抽象クラス(abstract class)は、直接インスタンス化できないクラスです。これは他のクラスの設計図として機能し、サブクラスが従うべき共通の構造を定義します。abstract キーワードを使用して作成します:
abstract class Shape {
String color;
Shape(this.color);
void describe() {
print('A $color shape');
}
}
class Circle extends Shape {
double radius;
Circle(String color, this.radius) : super(color);
}
void main() {
// Shape s = Shape('red'); // エラー!抽象クラスはインスタンス化できません
var circle = Circle('blue', 5.0);
circle.describe(); // A blue shape
}抽象クラスは以下を持つことができます:
- 実装を持つ通常のメソッド
- コンストラクタ
- プロパティ
サブクラスは、通常の継承と同様にこれらのメンバを継承します。主な違いは、抽象クラス自体のインスタンスを作成できないことです。具体的なサブクラスを使用する必要があります。
自分で試してみよう
import 'vehicle.dart';
void main() {
// TODO: brand が 'Toyota'、year が 2022、doors が 4 の Car を作成する
// TODO: car に対して displayInfo() を呼び出す
// TODO: "Doors: [doors]" を出力する
// TODO: car に対して honk() を呼び出す
// TODO: 空行を出力する
// TODO: brand が 'Harley'、year が 2021、hasSidecar が false の Motorcycle を作成する
// TODO: motorcycle に対して displayInfo() を呼び出す
// TODO: "Has sidecar: [hasSidecar]" を出力する
// TODO: motorcycle に対して revEngine() を呼び出す
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ