【Flutter】extendsについての基礎理解とimplementsとの違い

Flutter基礎

Flutterにおいてextendsをよく見るので理解を深めたくこの記事を書きました。
extendsの使い方やimplementsとの違いを知りたい方はぜひご覧ください。

extentsとは

Flutterにおけるextendsとは

  • クラスが別のクラスから継承していることを示すために使用されるキーワード

です。
extendsというとは日本語で拡張という意味です。

Cambridge英語辞書の記載

to add to something in order to make it bigger or longer
何かを大きくしたり長くしたりするために追加すること

公式には以下のような記載がありました。

Use extends to create a subclass, and super to refer to the superclass:
サブクラスを作成するには extends を使用し、スーパークラスを参照するには super を使用します。

superについての説明はここでは省略しますが、Dartでは、親クラス(superクラス)・子クラス(サブクラス)が存在し、親クラスのメソッドなどを継承して子クラスで使用するために”extends”を使用します。

Extend a class
Learn how to create subclasses from a superclass.

簡単な例で言うと、

class  Animal  {
  void makeSound() {
     print ( "Animal sound" ); 
  }
}

 class Dog extends Animal {
   void makeSound() {
     print ( "Bark" ); 
  }
}
  • Animalクラスが親クラス(superclass)
  • Dogクラスが子クラス(subclass)

で、「DogクラスがAnimalクラスを継承した」ということになります。

Flutterにおいてどのように使用するか

実際にFlutterで使用する場合は以下のような用途で使用できます。

  • 継承して新しいクラスを作成
  • 親クラスのすべてのプロパティとメソッドを継承
  • 新しいプロパティを追加し既存のものをオーバーライドする

extends 参考例

継承して新しいクラスを作成

class  Animal {
}

 class Dog extends Animal {
}

Dogクラスが親クラスであるAnimalクラスを継承しています。

親クラスのすべてのプロパティとメソッドを継承

class Person {
  String name;

  Person(this.name);

  void greet() {
    print('こんにちは、$nameです');
  }
}

class Student extends Person {
  Student(String name) : super(name);
}

void main() {
  Student student = Student('太郎');
  print(student.name);   // 太郎
  student.greet();       // こんにちは、太郎です
}

親クラスであるPersonクラスのプロパティnameを継承して子クラスStudentで使用しています。

また、greetという関数についても親クラスから継承して使用することが可能です。

新しいプロパティを追加したり既存のものをオーバーライドする

class Student extends Person {
  int grade; // 新しいプロパティ

  Student(String name, this.grade) : super(name);
}

void main() {
  Student student = Student('花子', 3);
  print(student.name);   // 花子(親から継承)
  print(student.grade);  // 3(子で追加)
}

子クラスであるStudentにgradeという新しいプロパティを追加することができます。

この場合だと、gradeという新しく追加したプロパティも親クラスであるPersonから継承したnameも使用できる。

class  Animal  {
  void makeSound() {
     print ( "Animal sound" ); 
  }
}

 class Dog extends Animal {
  @override
   void makeSound() {
     print ( "Bark" ); 
  }
}

親クラスであるAnimalからmakeSound関数を継承し、子クラスで独自にカスタムすることが可能になります。

@overrideをつけることで、子クラスのタイポなどの際にコンパイルエラーが発生するため、「この関数はオーバーライドするよ・上書きするよ」明示的にすることをDartでは推奨しています。

class Dog extends Animal {
  @override
  void makeSond() { // ← タイポでエラーに!
    print("Bark");
  }
}

Implements

extendsとよく比較されるものでimplementsがあります。

impementsとは

implemnetsとは

  • 他のクラスをインターフェイスとして使用するための宣言

です。

公式には以下のような記載がありました。

A class implements one or more interfaces by declaring them in an implements clause and then providing the APIs required by the interfaces. 

クラスは、implements 句でインターフェイスを宣言し、インターフェイスに必要な API を提供することで、1 つ以上のインターフェイスを実装します。

Classes
Summary of classes, class instances, and their members.

ここでいう「APIを提供する」というのは、メソッド名や引数の型など継承元から完全一致で実装することを示します。

つまり、implementsキーワードを使用したクラスのメソッドやプロパティを使用することができます。
(implementsしたクラスのメソッドは全て宣言する必要あり)
これでBというインターフェイス・中継役のクラスをAで使用することができます。

implementsの特徴としては、以下2つです。

  • implementsで実装したクラスにはインターフェイスのメソッドを全て定義する必要あり
  • クラスは複数implementsすることが可能
abstract class Repository {
  Future<void> save();
}

class ApiRepository implements Repository {
  @override
  Future<void> save() async {}
}

class LocalRepository implements Repository {
  @override
  Future<void> save() async {}
}

implementsする場合はインターフェイス(Repositoryクラス)の関数を全て定義する必要がある
ここではsaveメソッドをオーバーライドして別のクラスで使用している

class A implements B, C, D {}

上記のように複数のインターフェイスをimplementsすることが可能なことも特徴の一つです。

extendsとimplementsの違い

extendsとimplementsの違いとしては、2つでメソッドの定義と複数クラス実装できるかどうかです。

■メソッドの定義

  • extendsは必ず全てのメソッドを継承したクラスで実装しなくても良い
  • implemtensは必ずimplenensしたクラスでインターフェイスのメソッドを定義する必要がある
/// extendsの場合
class Animal {
  void eat() {
    print('eat');
  }

  void sleep() {
    print('sleep');
  }
}

class Dog extends Animal {
  // eat, sleep を書いていない
  // でも OK(親の実装をそのまま使う)
}

void main() {
  final dog = Dog();
  dog.eat();   // eat
  dog.sleep(); // sleep
}

/// implementsの場合

// ↓ これだとエラー
class BadDog implements Animal {
  @override
  void eat() {}
  // sleep がない → コンパイルエラー
}

// 全てを必ず実装
class Dog implements Animal {
  @override
  void eat() {
    print('dog eats');
  }

  @override
  void sleep() {
    print('dog sleeps');
  }
}

■複数クラスの実装

  • extendsは複数のクラスを継承することはできない
  • implemtensは複数のクラスをimplementsすることが可能
// exntendsの場合エラーに
class Animal {
  void eat() {}
}

class Pet {
  void play() {}
}

// Dartでは不可
class Dog extends Animal, Pet {}
// implementsの場合、複数OK
class Dog implements Animal, Pet {
  @override
  void eat() {
    print('eat');
  }

  @override
  void play() {
    print('play');
  }
}

最後に

Stateless Widget等何か作成した際に必ずでてくるextendsについて簡単にまとめました。implementsとの違いも知ることでより深く理解できたと思います。

こういった普段何気なく使っているがどういう意図のものか知らない部分についても理解を深めていきたいですね。

ではまた。

コメント

タイトルとURLをコピーしました