Menu
Coddy logo textTech

ファクトリコンストラクタ

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

ファクトリコンストラクタは、常に新しいインスタンスを作成するとは限らない特別なコンストラクタです。通常のコンストラクタとは異なり、ファクトリコンストラクタは既存のインスタンス、サブタイプ、あるいは(ヌル許容の場合)nullを返すことさえできます。これは factory キーワードを使用して宣言します。

class Logger {
  static final Logger _instance = Logger._internal();
  
  // プライベートな名前付きコンストラクタ
  Logger._internal();
  
  // ファクトリコンストラクタ
  factory Logger() {
    return _instance;
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

この例では、ファクトリコンストラクタは常に同じインスタンスを返します。何度 Logger() を呼び出しても、同一のオブジェクトが取得されます。このパターンは、シングルトンを実装するためによく使用されます。

ファクトリコンストラクタは、重要な点で通常のコンストラクタとは異なります。ファクトリコンストラクタは、新しいインスタンスを全く作成しない可能性があるため、this にアクセスできません。代わりに、オブジェクトを明示的に返す必要があります:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

ファクトリコンストラクタは、キャッシュされたオブジェクトを返したり、オブジェクトプールを実装したり、入力パラメータに基づいてどのサブタイプをインスタンス化するかを決定したりするなど、インスタンスの生成を制御する必要がある場合に便利です。

challenge icon

チャレンジ

簡単

シンプルな文字列入力に基づいて、さまざまなタイプの通知を作成するファクトリコンストラクタを使用した通知システムを構築しましょう。

コードを整理するために、2つのファイルを作成します:

  • notification.dart: すべての通知タイプのベースとなる Notification クラスを定義します。クラスには以下を含める必要があります:
    • String message フィールド
    • メッセージを初期化するプライベートな名前付きコンストラクタ Notification._internal
    • type パラメータに基づいて異なる通知サブタイプを返すファクトリコンストラクタ Notification(String type, String message)
      • type が 'email' の場合は、EmailNotification を返します
      • type が 'sms' の場合は、SMSNotification を返します
      • それ以外の場合は、PushNotification を返します
    • Sending: [message] と出力する send() メソッド

同じファイル内に、Notification を継承する3つのサブクラスを作成します:

  • EmailNotification: send() をオーバーライドして Email: [message] と出力します
  • SMSNotification: send() をオーバーライドして SMS: [message] と出力します
  • PushNotification: send() をオーバーライドして Push: [message] と出力します

各サブクラスには、message を受け取り、super._internal(message) を使用して親クラスに渡すコンストラクタが必要です。

  • main.dart: 通知クラスをインポートし、ファクトリコンストラクタを使用して3つの通知を作成します:
    • メッセージが 'Welcome!' のメール通知
    • メッセージが 'Your code is 1234' のSMS通知
    • メッセージが 'New update available' のプッシュ通知
    上記の順序で各通知の send() を呼び出します。

期待される出力:

Email: Welcome!
SMS: Your code is 1234
Push: New update available

チートシート

ファクトリコンストラクタは、factoryキーワードを使用して宣言される特別なコンストラクタで、常に新しいインスタンスを作成するとは限りません。通常のコンストラクタとは異なり、既存のインスタンス、サブタイプ、またはnullを返すことができます。

ファクトリコンストラクタはthisにアクセスできず、明示的にオブジェクトを返す必要があります。

シングルトンパターンの例:

class Logger {
  static final Logger _instance = Logger._internal();
  
  Logger._internal(); // プライベートな名前付きコンストラクタ
  
  factory Logger() {
    return _instance; // 常に同じインスタンスを返す
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

異なるサブタイプを返す例:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

ファクトリコンストラクタは、キャッシュされたオブジェクトを返す、オブジェクトプールを実装する、または入力パラメータに基づいてどのサブタイプをインスタンス化するかを決定するなど、インスタンスの作成を制御するのに役立ちます。

自分で試してみよう

import 'notification.dart';

void main() {
  // TODO: メッセージが 'Welcome!' のメール通知を作成する
  
  // TODO: メッセージが 'Your code is 1234' のSMS通知を作成する
  
  // TODO: メッセージが 'New update available' のプッシュ通知を作成する
  
  // TODO: 各通知に対して順番に send() を呼び出す
}
quiz icon腕試し

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

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