🤖
Rubyで学ぶリポジトリパターン (Repository Pattern)
1. どんなもの?
リポジトリパターンは、ドメインロジックとデータアクセスロジックを分離するためのデザインパターンです。
データベースへのクエリを直接記述するのではなく、「リポジトリ」と呼ばれるクラスを通じて、データの取得や保存を行います。
例えば、複数のデータソース(SQLデータベース、API、キャッシュなど)を統一されたインターフェースで扱う場合に役立ちます。
2. 通常の実装方法と比べてどこがすごいの?
通常の方法
データベース操作を直接モデルやコントローラー内に記述する場合、以下の課題が発生します。
class NotificationManager
def initialize(users)
@users = users
end
def send_notifications
# データアクセスロジック
active_users = @users.select { |user| user[:active] }.sort_by { |user| user[:created_at] }.reverse
# ビジネスロジック
active_users.each do |user|
puts "Sending notification to #{user[:name]}"
end
end
end
users = [
{ name: "Alice", active: true, created_at: Time.now - 3600 },
{ name: "Bob", active: false, created_at: Time.now - 7200 },
{ name: "Carol", active: true, created_at: Time.now - 1800 }
]
manager = NotificationManager.new(users)
manager.send_notifications
-
課題:
- データアクセスロジックとビジネスロジックが混在しコードが読みにくく、変更に強くない。
- データソースの変更が難しい(例えばハッシュからSQLデータベースに変更する場合など)。
リポジトリパターンの利点
リポジトリパターンを使うと、データ操作をリポジトリクラスに委譲できるため、コードの分離と再利用性が向上します。
# データアクセスロジック
class UserRepository
def initialize(users)
@users = users
end
def active_users
@users.select { |user| user[:active] }.sort_by { |user| user[:created_at] }.reverse
end
end
# ビジネスロジック
class NotificationManager
def initialize(repository)
@repository = repository
end
def send_notifications
active_users = @repository.active_users
active_users.each do |user|
puts "Sending notification to #{user[:name]}"
end
end
end
users = [
{ name: "Alice", active: true, created_at: Time.now - 3600 },
{ name: "Bob", active: false, created_at: Time.now - 7200 },
{ name: "Carol", active: true, created_at: Time.now - 1800 }
]
repository = UserRepository.new(users)
manager = NotificationManager.new(repository)
manager.send_notifications
-
利点:
- データアクセスロジックをリポジトリに集中させることで、コードの可読性と再利用性が向上。
- データアクセスロジック(UserRepository)とビジネスロジック(NotificationManager)が分離され、役割が明確になる。
- データソースが変更されても、リポジトリ内で対応できるため、他のコードへの影響を最小化。
- 通知方法を変更する場合も NotificationManager のみを修正すれば良いので、コードの可読性と保守性が向上する。
- データアクセスロジックをリポジトリに集中させることで、コードの可読性と再利用性が向上。
3. 技術や手法の"キモ"はどこにある?
-
統一されたインターフェース
- リポジトリは、データソースに依存しない統一されたインターフェースを提供します。
-
単一責任の原則(SRP)
- リポジトリはデータ操作に特化し、クラスからデータアクセスロジックを分離します。
-
依存性注入
- リポジトリを注入することで、異なるデータソースや条件に応じた実装を切り替え可能にします。
4. 実装例
例: JSONデータソースへの切り替え
データソースをハッシュからJSONファイルに切り替える例です。
require 'json'
class JsonUserRepository
def initialize(json_file_path)
@json_file_path = json_file_path
end
def active_users
users = JSON.parse(File.read(@json_file_path), symbolize_names: true)
users.select { |user| user[:active] }.sort_by { |user| user[:created_at] }.reverse
end
end
json_repo = JsonUserRepository.new("users.json")
puts json_repo.active_users
- 実装ポイント
- データソースをJSONファイルに変更する場合、別のリポジトリを用意するだけでよく、他のクラスへの影響はない。
Railsで実装するとしたら...
Rails では ActiveRecord があるので、あまりリポジトリパターンを使う必要はありませんが、以下のように実装できます。
例えば、リポジトリを使って、アクティブユーザーを取得するコードを統一します。
class UserRepository
def initialize(scope = User)
@scope = scope
end
def active_users
@scope.where(active: true).order(created_at: :desc)
end
end
class UsersController < ApplicationController
def index
repository = UserRepository.new
@users = repository.active_users
end
end
-
実装ポイント:
- データソースが変更されても、リポジトリ内で対応できるため、コントローラーへの影響を最小化。
この例では ActiveRecord を使っていますが、他のデータソース(API、キャッシュなど)を使っている場合にリポジトリパターンが有効です。
5. 議論はあるか?
メリット
- データアクセスロジックを分離することで、コードの可読性と再利用性が向上。
- データソースが変更されても、リポジトリ内で対応可能。
- テストが容易になる(リポジトリのモックを利用可能)。
デメリット
- リポジトリクラスが増えると管理が煩雑になる。
- 簡単なプロジェクトではオーバーヘッドとなる可能性がある。
議論
リポジトリパターンは、複雑なデータアクセスロジックが必要なプロジェクトで非常に有効ですが、シンプルなプロジェクトでは過剰設計となる場合があります。適切な範囲で利用することが重要です。
6. まとめ
リポジトリパターンは、データアクセスロジックを分離し、コードの可読性と拡張性を高めるデザインパターンです。
このパターンを適切に活用することで、柔軟で保守性の高いアプリケーション設計が可能になりますが、過剰設計にならないよう注意する必要があります。
Discussion