🌊

【Flutter】コンストラクタまとめ

2025/02/06に公開

目的

コンストラクタの復習です

結論

Dartには、「生成的コンストラクタ」「ファクトリ」「定数コンストラクタ」と三種類のコンストラクタが用意されているようです。さらに生成的コンストラクタには「Automatic field initialization」「Named Constructors」「Redirecting Constructors」「Initializer Lists」といった特徴が備わっていることがわかりました。

↑ということがわかった🤧

生成的コンストラクタ(Generative Constructors)

〈説明〉

  • クラスの「普通の」コンストラクタ
  • newやコンストラクタ呼び出しで新しいオブジェクトを作るときに利用

〈使い道〉

  • オブジェクトの初期値を設定したり、初期化時に必要な処理を実行する場合に使う

Automatic Field Initialization

〈説明〉

  • コンストラクタの引数が、そのままクラスのフィールド(プロパティ)の初期化に使われる仕組み
  • 「this.変数名」を使うと、自動的に引数の値がフィールドに代入される

〈使い道〉

  • コードが短くなり、フィールドの初期化が簡単に書ける
class Person {
  String name;
  int age;
  
  // 生成的コンストラクタ
  Person(this.name, this.age);
}

void main() {
  final p = Person("太郎", 16);
}

名前付きコンストラクタ(Named Constructors)

〈説明〉

  • クラスに複数の初期化方法を用意するため、コンストラクタに名前を付けることができる
  • 同じクラス内で異なる引数や処理でインスタンスを作るときに便利

〈使い道〉

  • 用途ごとに初期化方法を分けることで、コードの可読性と柔軟性が向上
class Rectangle {
  int width, height;
  
  // デフォルトの生成的コンストラクタ
  Rectangle(this.width, this.height);
  
  // 名前付きコンストラクタ:正方形を作るためのコンストラクタ
  Rectangle.square(int size)
    : width = size,
      height = size;
}

void main() {
  final rect = Rectangle(10, 20);
  final square = Rectangle.square(15);
}

リダイレクトコンストラクタ

〈説明〉

  • あるコンストラクタから別のコンストラクタへ処理を引き継ぐ機能
  • 重複した初期化コードを避け、1つの主要なコンストラクタにまとめたい場合に利用

〈使い道〉

  • 複数の名前付きコンストラクタで似た処理を行うとき、その処理を一箇所に集約し、コードの重複を防ぐ
class Point {
  int x, y;
  
  // デフォルトの生成的コンストラクタ
  Point(this.x, this.y);
  
  // 転送コンストラクタ:原点(0,0)のポイントを作る
  Point.origin() : this(0, 0);
}

void main() {
  final p1 = Point(3, 4);
  final origin = Point.origin();
}

Initializer Lists

〈説明〉

  • コンストラクタ実行前にフィールドを初期化するための構文
  • final変数や、コンストラクタ本体に入る前に値を設定する必要がある場合に使われる

〈使い道〉

  • 計算結果をもとにフィールドを初期化したいときや、スーパークラスのコンストラクタを呼ぶ前に値を設定する場合に使う
class Circle {
  final double radius;
  final double area;
  
  // イニシャライザリストを使用してareaを計算
  Circle(this.radius) : area = 3.14 * radius * radius;
}

void main() {
  final c = Circle(2.0);
  print(c.area);  // 面積が表示される
}

ファクトリーコンストラクタ(Factories)

〈説明〉

  • factoryキーワードを用いて定義するコンストラクタ
  • 必ずしも新しいインスタンスを生成せず、キャッシュ済みのオブジェクトやサブクラスのインスタンスを返すなど柔軟な初期化が可能

〈使い道〉

  • シングルトンパターン(クラスのインスタンスを1つだけにする)や、条件によって返すオブジェクトを変えたい場合に利用
class Logger {
  static final Logger _instance = Logger._internal();
  
  // プライベートコンストラクタ
  Logger._internal();
  
  // ファクトリーコンストラクタは常に同じインスタンスを返す
  factory Logger() {
    return _instance;
  }
}

void main() {
  final log1 = Logger();
  final log2 = Logger();
  
  // log1 も log2 もハッシュコードが同じになる
  print(log1.hashCode);
  print(log2.hashCode);
}

定数コンストラクタ(Constant Constructors)

〈説明〉

  • コンパイル時に決定できる不変(変更不可)のオブジェクトを作るためのコンストラクタ
  • constキーワードを使用してオブジェクトを作ると、そのインスタンスはプログラム全体で一定(immutable)となり、同じ値のオブジェクトが再利用される

〈使い道〉

  • 変更不要なデータ(例:座標、設定値、固定のカラーコードなど)を扱うときに使う
  • 同じ値のインスタンスを使い回すことで、メモリ効率が向上するメリットもある
class ImmutablePoint {
  final int x;
  final int y;
  
  // 定数コンストラクタ:フィールドはすべてfinalでなければならない
  const ImmutablePoint(this.x, this.y);
}

void main() {
  // constで宣言するとコンパイル時にインスタンス化される
  const point1 = ImmutablePoint(1, 2);
  const point2 = ImmutablePoint(1, 2);
  const point3 = ImmutablePoint(1, 3);
 
  print(point1.hashCode); // 174866081
  print(point2.hashCode); // 174866081
  print(point3.hashCode); // 239670087
}

参考にした記事

https://dev.classmethod.jp/articles/about_dart_constructors/#item_01

Discussion