🙆

Rubyで学ぶファクトリーパターン (Factory Pattern)

2025/01/13に公開

1. どんなもの?

ファクトリーパターンは、オブジェクトを生成する仕組みをカプセル化し、生成過程の詳細を隠蔽するデザインパターンです。
このパターンを使用することで、クライアントコード(利用する側)は具体的なクラス名や生成手順を知らずに、オブジェクトを作成できます。

2. 通常の実装方法と比べてどこがすごいの?

通常の方法

class User
  def initialize(name)
    @name = name
  end
end

user = User.new("Alice")
  • クラス名や初期化手順を直接書く必要がある。
  • オブジェクト生成の変更があると、呼び出し元のコードを修正する必要がある。

ファクトリーパターンの場合

class UserFactory
  def self.create(name)
    User.new(name)
  end
end

user = UserFactory.create("Alice")
  • クラス名や初期化手順を隠蔽。
  • オブジェクト生成方法を一元管理でき、変更が容易。

3. 技術や手法の”キモ”はどこにある?

  • インターフェースの統一:
    • クライアントコードが具体的なクラス名や生成方法に依存しないため、柔軟性が向上します。
  • 生成ロジックの集中管理:
    • オブジェクト生成ロジックを1つの場所にまとめることで、メンテナンスが容易になります。

4. 実装例

例: Factory Bot

Factory Bot ではファクトリーパターンとして Rails の ActiveRecord のインスタンスを生成します。

class User < ApplicationRecord
end

# Factory Botを利用した生成
FactoryBot.define do
  factory :user do
    name { "Alice" }
    email { "alice@example.com" }
  end
end

# 利用例
user = FactoryBot.create(:user)
  • 実装ポイント:
    • データベースレコードの生成ロジックを一元管理。
    • テストデータの管理と再利用性が向上。

5. 議論はあるか?

メリット

  • オブジェクト生成が簡潔かつ柔軟になる。
  • クライアントコードが生成ロジックに依存しなくなる。

デメリット

  • 単純なプロジェクトではオーバーヘッドが発生する可能性がある。
    • 小さなプロジェクトでは不必要に複雑化する可能性がある。
      • 例: ファクトリーパターンを導入しない場合とする場合の比較
      • # ファクトリーパターンを利用しない場合
        user = User.new(name: "Alice", email: "alice@example.com")
        
        # ファクトリーパターンを利用する場合
        class UserFactory
          def self.create(attrs)
            User.new(attrs)
          end
        end
        user = UserFactory.create(name: "Alice", email: "alice@example.com")
        
      • ファクトリーパターンを採用すると、ファクトリークラス(オブジェクト生成を一元管理するクラス)と生成ロジック(オブジェクト生成に必要な追加の条件分岐や設定)が必要になる。
      • プロジェクトの規模が小さい場合、わざわざファクトリークラスを作成・管理する必要がない場合が多く、ファクトリクラス自体のメンテナンスが負担になることがあります。
      • 小さなプロジェクトや単純なオブジェクト生成であれば直感的に理解できるコードが、ファクトリパターンの導入によって抽象化され、読みづらくなる場合があります。
  • 生成ロジックが複雑になると、ファクトリクラス自体が膨らむ可能性がある。
    • 例: 抽象化が過剰な場合
      • 下記のようなコードは、特定の条件で通知を送る必要がある場合には便利ですが、単純に1種類の通知だけを送るだけの小規模プロジェクトでは過剰です。
    • class NotificationFactory
        def self.create(type)
          case type
          when :email
            EmailNotification.new
          when :sms
            SmsNotification.new
          else
            raise "Unknown notification type"
          end
        end
      end
      
      notification = NotificationFactory.create(:email)
      notification.send
      

ファクトリーパターンを適用すべき場面

ファクトリーパターンは、以下のようにオブジェクト生成が複雑な場合に有効です

  • 条件に応じて異なるクラスのインスタンスを返す必要がある。
  • 生成プロセスに複数のステップがある。
  • 生成ロジックを複数の場所で再利用する必要がある。

一方で、以下のような場合はファクトリーパターンを使わない方がよいでしょう

  • プロジェクトが小規模である。
  • オブジェクト生成がシンプルで、ロジックが複雑ではない。

7. まとめ

ファクトリーパターンは、オブジェクト生成を抽象化することで、クライアントコードの可読性を向上させ、生成ロジックを集中管理できる強力な手法です。

適切に利用すれば、保守性と拡張性を大幅に向上させることができます。設計の選択肢として、ぜひ取り入れてみてください。

GitHubで編集を提案

Discussion