Menu
Coddy logo textTech

抽象メソッド

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

抽象メソッドは、本体を持たない抽象クラス内で宣言されたメソッドです。これはメソッドのシグネチャを定義しますが、実装は各サブクラスに委ねられます。抽象クラスを継承するクラスは、すべての抽象メソッドをオーバーライドしなければなりません。そうしない場合、そのクラスも抽象クラスになります。

abstract class Animal {
  // 抽象メソッド - ボディがなく、サブクラスで実装する必要があります
  String makeSound();

  // 具象メソッド - ボディがあり、すべてのサブクラスで共有されます
  void breathe() {
    print('Breathing...');
  }
}

class Dog extends Animal {
  @override
  String makeSound() {
    return 'Woof!';  // 実装を提供する必要があります
  }
}

class Cat extends Animal {
  @override
  String makeSound() {
    return 'Meow!';  // 異なる実装、同じシグネチャ
  }
}

サブクラスが抽象メソッドの実装を忘れた場合、Dartはコンパイルエラーを発生させます。これこそが重要な点です。抽象メソッドは契約を強制します。すべてのサブクラスはそのメソッドを持つことが保証されるため、抽象型のどのインスタンスに対しても安全にそのメソッドを呼び出すことができます。

// 抽象型を変数型として使用できます
Animal a = Dog();
print(a.makeSound());  // ワンワン!

Animal b = Cat();
print(b.makeSound());  // ニャー!

抽象メソッドは、抽象クラス内の具象メソッドとは異なります。具象メソッドはボディを持ち、そのまま継承されます。抽象メソッドはボディを持たず、必ずオーバーライドされる必要があります。

同じ抽象クラス内で両方を混在させることで、一部の振る舞いを共有しつつ、他の振る舞いについてはサブクラスに独自の定義を強制することができます。

特徴抽象メソッド具象メソッド
ボディの有無なしあり
オーバーライド必須はいいいえ
目的規約の強制振る舞いの共有
定義場所抽象クラスのみ任意のクラス
challenge icon

チャレンジ

簡単

抽象メソッドの実際の動作を示す図形計算機を作成しましょう。各図形が異なる方法で実装する必要がある抽象メソッドを持つ抽象クラスを定義し、それらの図形を共通のインターフェースを通じて使用します。

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

  • shape.dart: final フィールド color (String) とそれを初期化するコンストラクタを持つ抽象クラス Shape を定義します。2つの抽象メソッド double area()double perimeter() を宣言します。また、A [color] shape with area: [area] and perimeter: [perimeter] と出力する具体的なメソッド describe() を追加します。area()perimeter() は抽象メソッドであるため、各サブクラスが独自の計算を提供しますが、describe() はオーバーライドされることなくすべてのサブクラスで動作します。
  • circle.dart: Shape を継承する Circle クラスを作成します。final フィールド radius (double) を持ちます。そのコンストラクタは colorradius を受け取り、colorsuper に渡します。area() を実装して 3.14 * radius * radius を返し、perimeter() を実装して 2 * 3.14 * radius を返すようにします。
  • rectangle.dart: Shape を継承する Rectangle クラスを作成します。final フィールド widthheight (ともに double) を持ちます。そのコンストラクタは colorwidthheight を受け取り、colorsuper に渡します。area() を実装して width * height を返し、perimeter() を実装して 2 * (width + height) を返すようにします。
  • main.dart: すべてのファイルをインポートします。color が 'red' で radius が 5.0Circle と、color が 'blue' で width が 4.0、height が 6.0Rectangle を作成します。各図形で describe() を呼び出します。次に、両方の図形を含む List<Shape> を作成し、リストをループして、各図形の Area: [area] を出力します。

期待される出力:

A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0

チートシート

抽象メソッドとは、抽象クラス内で宣言され、本体(実装)を持たないメソッドのことです。サブクラスは、独自の実装を提供するために、このメソッドをオーバーライドする必要があります。

abstract class Animal {
  // 抽象メソッド - 本体なし
  String makeSound();

  // 具象メソッド - 本体あり
  void breathe() {
    print('Breathing...');
  }
}

サブクラスは、すべての抽象メソッドを実装しなければなりません:

class Dog extends Animal {
  @override
  String makeSound() {
    return 'Woof!';
  }
}

class Cat extends Animal {
  @override
  String makeSound() {
    return 'Meow!';
  }
}

抽象型を変数の型として使用することができます:

Animal a = Dog();
print(a.makeSound());  // Woof!

Animal b = Cat();
print(b.makeSound());  // Meow!
機能抽象メソッド具象メソッド
本体の有無なしあり
オーバーライドの必須性はいいいえ
目的規約の強制振る舞いの共有
定義場所抽象クラスのみ任意のクラス

自分で試してみよう

import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';

void main() {
  // TODO: color が 'red' で radius が 5.0 の Circle を作成します

  // TODO: color が 'blue'、width が 4.0、height が 6.0 の Rectangle を作成します

  // TODO: circle に対して describe() を呼び出します

  // TODO: rectangle に対して describe() を呼び出します

  // TODO: 両方の図形を含む List<Shape> を作成します

  // TODO: リストをループで回し、各図形に対して "Area: [area]" を出力します
}
quiz icon腕試し

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

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