はじめに
リポジトリパターンとは何かを整理します。
リポジトリパターンとは
リポジトリパターン(Repository Pattern)は、データの取得や保存を行う処理をまとめるための設計パターンです。
例えば、ユーザーを取得する処理があるとします。
$user = $userRepository->findById($id);
呼び出し側は「ユーザーを取得する」ということだけを考えます。
その裏側で、
- データベースへ問い合わせる
- 外部APIを呼び出す
- キャッシュから取得する
といった処理はRepositoryが担当します。
利用する側は、どこからデータを取得しているかを意識する必要はありません。
なぜRepositoryを作るのか
例えば、アプリケーションのあちこちでSQLを書いているとします。
$user = DB::table('users')
->where('id', $id)
->first();
このようなコードが複数の場所に存在すると、取得方法を変更したいときに修正箇所が増えてしまいます。
そこで、データアクセスをRepositoryへ集約します。
$user = $userRepository->findById($id);
こうしておくことで、取得方法が変わっても修正はRepositoryの中だけで済みます。
データベースだけではない
Repositoryという名前から、データベース専用の仕組みだと思われることがあります。
しかし、Repositoryが扱うデータソースはデータベースに限りません。
例えば、
- REST API
- GraphQL API
- Redis
- ファイル
などからデータを取得する実装でもRepositoryを利用できます。
重要なのは、
「どこから取得するか」
ではなく、
「データの取得方法を隠す」
ことです。
Clientクラスとの違い
外部APIを利用する場合、
$githubClient->createIssue();
のようなClientクラスを作ることがあります。
Clientの役割は、HTTP通信を行い、API仕様に従ってリクエストを送受信することです。
一方でRepositoryは、
$issueRepository->findById($id);
のように、アプリケーションから見たデータの窓口になります。
Repositoryの内部でClientを利用することはありますが、役割は異なります。
Clientは通信を担当し、Repositoryはデータの取得や保存を担当します。
Repositoryの中でAPIを利用することもある
例えば、ユーザー情報を外部サービスから取得するシステムがあるとします。
その場合、
Application
│
▼
UserRepository
│
▼
UserApiClient
│
▼
外部API
という構成になることがあります。
アプリケーションはRepositoryだけを利用し、HTTP通信の詳細はClientへ任せます。
このように役割を分けることで、それぞれの責務が明確になります。
必ず使うべきなのか
現在では、Repositoryパターンは必ず導入すべきという考え方ではありません。
例えば、多くのORMはデータアクセスを抽象化する機能を備えています。
そのため、シンプルなアプリケーションではRepositoryを追加せず、ORMを直接利用することもあります。
一方で、
- 複数のデータソースを扱う
- データ取得の処理が複雑になる
- ドメインロジックとデータアクセスを分離したい
といった場合には、Repositoryパターンが役立ちます。
おわりに
リポジトリパターンは、データの取得や保存を一箇所へ集約し、アプリケーションからデータアクセスの詳細を隠すための設計パターンです。
データソースはデータベースに限らず、APIやキャッシュなどにも適用できます。
どのような場面でRepositoryを導入すると効果的なのかを理解しておくと、設計の選択肢を広げることができます。