LoginSignup
7
2

More than 1 year has passed since last update.

export 13.png

Query Object と Repository はいずれも、Data Mapper によってマッピングされたデータを得るために用いられます。

Query Object は端的に言ってしまえば言語内 DSL です。SQL を直接使ってデータを得る Transaction Script や Table Module で可能なことが、Data Mapper を利用してデータソースをすっかり隠蔽した Domain Model でできなくなってしまうと、パターンの選択肢として価値がなくなります。Data Mapper 層も、エンティティを得るという目的範囲においては (もちろん集計関数やウィンドウなどの SQL ならではの機能については別として)、SQL と同等レベルの高度な問い合わせに応える必要があるかもしれません。

Query Object は、検索条件を表す言語をオブジェクトで作るパターンです。構造化された言語文法の個々の要素 (クライテリアと呼ばれることもあります) が、オブジェクトのインスタンスとなる Composite パターン (GoF) で設計されます。複雑な問い合わせ担った場合、それは実質、SQL のクエリビルダになります。が、最終的に (単一または複数の) 主キーで行を指定するような形になった場合、Identity Map のキーを指定して、SQL を発行せずにインスタンスを得ることができます。Foreign Key Mapping を辿って Lazy Load で関連データを取得するとき、その問い合わせのほとんどは、主キーを指定しただけの Query Object になります。

Query Object があらゆる問い合わせを表現できる言語であるのに対して、Repository はごく限られた数のメソッドしか持ちません。

Domain Model はできるだけ、データソースの存在を忘れて、ビジネスロジックに集中した方が純度が上がります。どこからともなく無限のストレージリソースが提供されている、といった雑な認識が可能な抽象があってくれれば、その詳細はどう実現されていても気にしなくていいのが理想です。そのようなデータ倉庫(=Repository)の抽象オブジェクト(インターフェース)を設けるのが、Repository パターンです。

Repository のメソッドは Domain Model に現れる「データソースへの検索要求」に応じて、必要最小限の数が設けられます。メソッドには、検索条件引数をせいぜいひとつかふたつしか持たない程度の表現力しか持たせないのがセオリーです。どんな問い合わせにでも応じられる Repository を作ろうとするのはアンチパターンです。

Domain Model のメリットのひとつは、データソースと分離した純粋な単体テストです。もし Repository のインターフェースが簡単にモックオブジェクト化できないものだったら、単体テストはデータベースを求めはじめます。Domain Model は、どこで何をしているかわからないオブジェクト群の連携です。操作範囲が明らかな Table Module パターンよりも、テスト用データベースの準備が困難です。抽象化されているぶん、Transaction Script の場合よりも困難と言えるかもしれません。誰でも気軽にモックにできる単純さが、良い Repository の必要条件です。

Query Object は可能な操作全て表現するもの、Repository は実際に要求されることにだけ端的に応えるもの、と、パターンを意識する状況が全く異なるのが、違いの本質です。つまりほとんどの場合、「Repository の具象を実装するときに、Query Object を使う」「Domain Model には Query Object を使わせない」となるのが、これらの個別技法パターンの利用パターンとなります。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2