🐦

【Dart】クラスの基本的な使い方

2022/11/30に公開

概要

Dartはオブジェクト指向言語でNull(Objectの子孫)以外の全てのオブジェクトがクラスのインスタンスです。
その為、Dartを学ぶ上でとても大切なクラスについて使い方をざっくりまとめました。

※概念的な説明(クラスとは・インスタンスとは)はなく、Dartでクラスを使用するメモのようなものになっています。

クラスの宣言方法

class キーワードの後に宣言したいクラス名を記載することで宣言できます。

下記に具体例を示しましたが、大枠このような構成になっています。

class クラスの名前 {
  // インスタンス変数
  // コンストラクタ
  // インスタンスメソッド
}

下記が実際のDartのクラスの具体例です。

インスタンス変数の宣言方法がやや異なっていますが、それぞれコメントで補足しています。

  • 全てのインスタンス変数は内部的にgetterを与えられます
  • finalで宣言されていないインスタンス変数は同じくsetterも与えられます
class Person {
  // インスタンス変数
  int? age; // null許容型
  final String name; // final変数
  String address = '東京都'; // 初期値を設定

  // コンストラクタ
  Person(this.name);

  // インスタンスメソッド
  void introduce() {
    print('私は$nameです');
  }
}

(Named ・Factory・Redirecting)Constructors

Dartには幾つかの種類のコンストラクタが存在しているらしく、
下記の記事を見るとそれぞれの特徴、実際の使われ方がとても分かりやすく説明されていました🙇🙇

【Dart】簡単なユーザクラスを利用してNamed,Redirecting,Factoryコンストラクタ理解

インスタンス(オブジェクト)の作成方法・変数/関数のアクセス方法

クラス名とコンストラクタを使用することでインスタンスの作成が可能です。

上記で作成したPersonクラスのインスタンスを作成してみます。

void main() {
  final taro = Person('太郎');
  taro.age = 10;
  taro.address = '京都府';

  taro.introduce(); // => 私は太郎です。京都府に住んでいる10歳です。
}

継承

extends キーワードを使用することでクラスを継承することができます

class Employee extends Person {
  String department;
  // superで親クラスのコンストラクタも呼んでいる
  Employee(String name, this.department) : super(name);
}

親クラスのインスタンス変数・メソッドを上書き

@overide キーワードを使用することで親クラスのインスタンス変数やメソッドを上書きすることが可能です。

class Employee extends Person {
  String department;

  Employee(String name, this.department) : super(name);

  
  void introduce() {
    print('私は$departmentに所属しています。');
  }
}

下記が実行結果です

void main() {
  final employee1 = Employee('花子', '営業');
  employee1.introduce(); //私は営業に所属しています。
}

FlutterでステートレスなWidgetを作成する際に、StatelessWidgets等を継承してbuildメソッドをoverrideしますね。

class MyWidget extends StatelessWidget {
  
  Widget build(BuildContext context) {
  }
}

親クラスのインスタンス変数・メソッドを継承されたクラスで呼び出す

super キーワードで親クラスのインスタンス変数やメソッドを呼び出すことが可能です。

class Employee extends Person {
  String department;

  Employee(String name, this.department) : super(name);

  
  void introduce() {
    super.introduce();
    print('私は$departmentに所属しています。');
  }
}

下記が実行結果になります。

void main() {
  final employee1 = Employee('花子', '営業');
  employee1.age = 25;
  employee1.address = '東京都';
  employee1.introduce(); 
  // 私は花子です。東京都に住んでいる25歳です。
  // 私は営業に所属しています。
}

Abstract(抽象)クラス

Abstract(抽象)クラスはインスタンス化することのできない継承されることを前提としたクラスです。

abstract のキーワードをclassの前につけることで宣言が可能です。

abstract class Animal {
  void walk();
}

class Dog extends Animal {
  void walk() {
    print('歩けるんだ僕は');
  }
}

FlutterのStatelessWidgetもAbstractクラスですね。
参照: flutter/packages/flutter/lib/src/widgets/framework.dart

abstract class StatelessWidget extends Widget {
  const StatelessWidget({ super.key });

  
  StatelessElement createElement() => StatelessElement(this);

  
  Widget build(BuildContext context);
}

Implicit Interfaces(暗黙的インターフェース)

DartではInterfaceといったキーワードは存在しません。
多言語(Java等)のInterfaceのような役割を行うために、implementsキーワードを用います。

exntendsとは異なり、クラスに組み込むとそのクラス(暗黙的インターフェース)にあるメソッドや変数を全て実装(implement)する必要があります。

class Person {
  final String name;

  Person(this.name);

  void introduce() {
    print('私は$nameです。');
  }
}

// Personの持つ全ての要素を実装(implement)してあげる必要がある
class Employee implements Person {
  final String name;
  String department;

  Employee(this.name, this.department);

  void introduce() {
    print('私は$nameで、$departmentに所属しています。');
  }
}

この辺の概念的な違い等は私の稚拙な説明より下記を読んで頂けると分かりやすいかと思います:bow:

Mixin

mixinキーワードを使用することで拡張するメソッドや状態を定義することが可能です。
withキーワードを使用することで実際に定義したmixinを使用することができます。

mixin Accounting {
  void fileTaxies() {
    print('あ、確定申告代わりにしときましたよ');
  }

  void askAccountant() {
    print('税理士に聞いてみましょう.....');
  }
}

class Person with Accounting {
  final String name; // finalは初期化後に変更不可

  Person(this.name);
}

実行結果は下記です

void main() {
  final taro = Person('太郎');
  taro.fileTaxies(); //あ、確定申告代わりにしときましたよ
}

実際にmixinが役に立つケースの説明等に関してはこちらがとても分かりやすかったです。

クラスメソッド・変数

staticキーワードを使用することでクラスメソッド・変数を定義することが可能です。

class Person {
  static const initialAge = 0;
  static void printFeature() {
    print('足が2つ。腕も2つ。');
  }
}

print(Person.initialAge) //=> 0
Person.printFeature() //=> '足が2つ。腕も2つ。'

参考

Discussion