📌

引数としてオブジェクトと値を受け取る場合の使い分け

2025/01/13に公開

普段コードを書いていて、メソッドの引数としてオブジェクトを渡すべきか、値を渡すべきか迷うことがあります。
なので、この記事では、Rubyでメソッドの引数としてオブジェクトと値を受け取る場合の使い分けについて、個人的な考えのまとめを書いておきます。

データを受け取って、それをレポート化するクラスを考えます。

ここで引数の data として、データを提供するオブジェクト(DataProvider)を受け取るか、データそのものを受け取るかを考えます。

class ReportGenerator
  def initialize(data)
    @data = data
  end

  def generate_report
    # レポート生成処理
  end
end

1. オブジェクト全体を渡す場合

判断基準

  • オブジェクトの他のメソッドやプロパティも利用する可能性がある場合。
  • オブジェクトの状態やライフサイクルを管理する必要がある場合。
  • クラス間の依存関係を明示的に示したい場合。
class ReportGenerator
  def initialize(data_provider)
    @data_provider = data_provider
  end

  def generate_report
    data = @data_provider.fetch_data
    # レポート生成処理
  end
end

class DataProvider
  def fetch_data
    # データを取得する処理
  end
end

data_provider = DataProvider.new
report_generator = ReportGenerator.new(data_provider)
report_generator.generate_report

メリット

  • 柔軟性が高く、将来的な拡張に対応しやすい。
  • オブジェクトに関する責務が明確で、コードの意図を理解しやすい。

デメリット

  • 必要以上に多くの情報(オブジェクト全体)を渡すことで、設計が複雑になる可能性がある。
  • 依存関係が増えるため、テストがやや複雑になる場合がある。

2. 特定の値だけを渡す場合

判断基準

  • オブジェクトの特定の値以外を使用する必要がない場合。
  • オブジェクトが重いリソースを持っている場合(大量のデータや外部接続)。
  • クラスの依存関係を最小限にしたい場合。
class ReportGenerator
  def initialize(data)
    @data = data
  end

  def generate_report
    # レポート生成処理
  end
end

data = { name: "Alice", age: 30 }
report_generator = ReportGenerator.new(data)
report_generator.generate_report

メリット

  • クラスの依存関係が少なくなり、シンプルな設計になる。
  • クラスの責務が明確化し、リファクタリングが容易。

デメリット

  • 拡張性が低くなる可能性がある(結果以外の機能が後で必要になった場合に修正が必要)。
  • 呼び出し側で結果を準備する手間が増える。

3. その他の考慮事項

  • 引数として渡す情報が、クラスやメソッドの責務と適合しているか?
    • クラスやメソッドが単一の責務に集中している場合、必要なデータのみを渡すことで責務を明確化できる。
  • 引数として渡された値やオブジェクトが、変更可能か(mutable)変更不可能か(immutable)?
    • 不変の値であれば、そのまま渡しても安全。
    • 渡す値が変更可能なデータであれば、変更が他の箇所に影響を及ぼす可能性があるため、コピーを渡すなどを検討する必要がある。
  • テストのしやすさ
    • 値だけを渡すと、モックやスタブを準備する必要がないため、簡単にテストを記述できる。
  • チームでの理解とコードベース上での一貫性
    • 開発チーム全体でコードの意図が理解されやすく、一貫性を保てる設計を選択することが重要
    • 「オブジェクトを渡すべき場合」と「値を渡すべき場合」を一貫して判断できるよう、ガイドラインを設けられると良い

まとめ

以下に一旦の判断基準としてまとめましたが、設計上の目的やオブジェクトの役割、システムの規模などの複数の理由によって変わってくるので、状況に応じて適切な方法を選択する必要がありそう。

状況 選ぶべき方法
オブジェクトの他のメソッドやプロパティを利用する可能性がある オブジェクト全体を渡す
オブジェクトの状態やライフサイクルを管理する必要がある オブジェクト全体を渡す
特定の値以外を使用しない場合 値だけを渡す
オブジェクトが重いリソース(ネットワーク接続、大量のデータなど)を持っている場合 値だけを渡す
クラスの依存関係を明示的にしたい オブジェクトBを引数として受け取る
クラスの責務を最小限にしたい 結果だけを引数として受け取る
GitHubで編集を提案

Discussion