Menu
Coddy logo textTech

Factoryパターン

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

Factoryパターンは、オブジェクトの生成を別のメソッドやクラスに委譲し、具体的なクラスを指定せずにオブジェクトを生成できるようにします。これは以前に学んだfactoryコンストラクタとは異なります。Factoryパターンは、生成ロジックを集中させ、入力に基づいて異なる型を返すことができる設計手法です。

さまざまな種類の通知を作成する必要があるシナリオを考えてみましょう。クライアントがどのクラスをインスタンス化するかを決定する代わりに、ファクトリがその決定を処理します:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

クライアントコードは EmailNotificationSMSNotification について知る必要はありません。単に特定のタイプの通知をファクトリに要求するだけです。これにより、新しい通知タイプの追加が容易になります。通知を作成するすべての箇所ではなく、ファクトリだけを修正すれば済むようになります。

オブジェクトの生成に複雑なロジックが含まれる場合、実装クラスをクライアントから隠蔽したい場合、または生成する具体的な型が実行時の条件に依存する場合に、Factoryパターンを使用します。

challenge icon

チャレンジ

簡単

Factoryパターンを使用してドキュメントジェネレーターを構築しましょう!集中管理されたファクトリを通じて、さまざまな種類のドキュメント(レポート、請求書、手紙)を作成するシステムを作成します。これにより、クライアント側のコードは具体的なドキュメントクラスについて知る必要がなくなります。

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

  • document_factory.dart: ここにドキュメントシステムを作成します:
    • Stringを返すgenerate(String content)メソッドを持つ抽象クラスDocument
    • Documentを実装する3つの具象クラス:
      • Report - そのgenerateメソッドは=== REPORT ===\n[content]\n=============を返します
      • Invoice - そのgenerateメソッドはINVOICE\n--------\n[content]\nTotal Dueを返します
      • Letter - そのgenerateメソッドはDear Reader,\n[content]\nSincerelyを返します
    • タイプ文字列("report""invoice"、または"letter")に基づいて適切なDocumentを返す静的メソッドcreate(String type)を持つDocumentFactoryクラス。不明なタイプの場合は、デフォルトとしてLetterを返します
  • main.dart: ドキュメントファクトリをインポートし、クライアントが具象クラスを知ることなく、ファクトリがどのように異なるドキュメントタイプを作成するかを示します:
    • ファクトリを使用してレポートを作成し、コンテンツSales increased by 25%で生成した結果を出力します
    • 空行を出力します
    • ファクトリを使用して請求書を作成し、コンテンツWidget x3 - $150で生成した結果を出力します
    • 空行を出力します
    • ファクトリを使用して手紙を作成し、コンテンツThank you for your orderで生成した結果を出力します

メインファイルがファクトリと抽象クラスDocument型のみとやり取りし、ReportInvoice、またはLetterオブジェクトを直接作成していないことに注目してください!

期待される出力:

=== REPORT ===
Sales increased by 25%
=============

INVOICE
--------
Widget x3 - $150
Total Due

Dear Reader,
Thank you for your order
Sincerely

チートシート

Factory パターンは、オブジェクトの生成を別のメソッドやクラスに委譲することで、具体的なクラスを指定せずにオブジェクトを生成できるようにします。生成ロジックは一元化され、入力に基づいて異なる型を返すことができます。

Factory パターンの基本構造:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

クライアントコードは、具体的な実装クラスではなく、Factory と抽象型のみを操作します。これにより、新しい型の追加が容易になります。Factory を修正するだけで済みます。

Factory パターンは以下のような場合に使用します:

  • オブジェクトの生成に複雑なロジックが含まれる場合
  • 実装クラスをクライアントから隠蔽したい場合
  • 生成する正確な型が実行時の条件に依存する場合

自分で試してみよう

import 'document_factory.dart';

void main() {
  // TODO: DocumentFactory.create() を使用してレポートを作成します
  // 次に、コンテンツ "Sales increased by 25%" で生成した結果を出力します
  
  // TODO: 空行を出力します
  
  // TODO: DocumentFactory.create() を使用して請求書を作成します
  // 次に、コンテンツ "Widget x3 - \$150" で生成した結果を出力します
  
  // TODO: 空行を出力します
  
  // TODO: DocumentFactory.create() を使用して手紙を作成します
  // 次に、コンテンツ "Thank you for your order" で生成した結果を出力します
}
quiz icon腕試し

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

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