18

この質問は、この問題に関する私の混乱を少し解消するのに非常に良い仕事をしましたが、サービスレイヤーの正確な制限がどうあるべきかについて信頼できる情報源を見つけるのに苦労しています.

この例では、本を扱っていて、著者別に本を取得したいとします。には、書籍の一意の識別子、著者名などの条件を受け入れるBookDataMapper一般的なメソッドを含めることができます。この実装は (論理的に) かなり簡単ですが、より複雑なクエリを必要とする複数の条件が必要な場合はどうすればよいでしょうか?get()

特定の出版社の特定の著者によって書かれたすべての本を取得したいとしましょう。BookDataMapper->get()メソッドを拡張して複数の条件を解析することも、 BookDataMapper->getByAuthorAndPublisher().

これらの[より具体的な]メソッドをサービス層に直接呼び出すBookDataMapper->get()か、複数の条件が渡されたより一般的なメソッドを呼び出す前に条件を解析することが望ましいですか? 後者のシナリオでは、サービス レイヤーがより多くの論理的な「重労働」を行い、データ マッパーをかなり単純なままにします。前者のオプションは、サービス レイヤーをほぼ完全に仲介者に減らし、条件付きロジックを のようなメソッドのデータ マッパーに任せますBookDataMapper->getByAuthorAndPublisher()

サービス層に条件を解析させることに関する明らかな懸念は、ドメイン ロジックの一部がデータ マッパーから漏れることです。(これはリンクされた質問hereで説明されています。ただし、サービス レイヤーが条件を処理する場合、ロジックはモデル レイヤーの外に出ません。コントローラーは$book_service->getByAuthorAndPublisher()関係なく呼び出します。

4

2 に答える 2

24

データ マッパーパターンは、何を行うべきかを示すだけで、実装方法は示しません。
したがって、このトピックのすべての回答は、各著者の個人的な好みを反映しているため、主観的なものとして扱う必要があります。

は通常、マッパーのインターフェースをできるだけシンプルに保つようにしています。

  • fetch()、ドメイン オブジェクトまたはコレクション内のデータを取得します。
  • save()、ドメイン オブジェクトまたはコレクションを保存 (既存の更新または新規の挿入)
  • remove()、ストレージ メディアからドメイン オブジェクトまたはコレクションを削除します

ドメイン オブジェクト自体に条件を保持します。

$user = new User;
$user->setName( 'Jedediah' );

$mapper = new UserMapper;
$mapper->fetch( $user );

if ( $user->getFlags() > 5  )
{
    $user->setStatus( User::STATUS_LOCKED );
}

$mapper->save( $user );

このようにして、インターフェイスをきれいに保ちながら、検索に複数の条件を設定できます。

これの欠点は、そのようなメソッドを持つためにドメイン オブジェクトから情報を取得するためのパブリック メソッドfetch()が必要なことですが、save().

マッパーとドメイン オブジェクトの相互作用に関する経験則「Tell Don't Ask」を実装する現実的な方法はありません。

「ドメインオブジェクトを本当に保存する必要があることを確認する方法は?」、あなたに思いつくかもしれませんが、それはここでカバーされており、コメントに豊富なコード例といくつかの便利なビットがあります.

アップデート

オブジェクトのグループを処理する場合は、単純なDomain Objectsではなく、さまざまな構造を処理する必要があります。

$category = new Category;
$category->setTitle( 'privacy' );

$list = new ArticleCollection;

$list->setCondition( $category );
$list->setDateRange( mktime( 0, 0, 0, 12, 9, 2001) );
// it would make sense, if unset second value for range of dates 
// would default to NOW() in mapper

$mapper = new ArticleCollectionMapper;
$mapper->fetch( $list );

foreach ( $list as $article )
{
    $article->setFlag( Article::STATUS_REMOVED );
}

$mapper->store( $list );

この場合、コレクションは美化された配列であり、さまざまなパラメーターを受け入れることができ、マッパーの条件として使用されます。また、マッパーがコレクションを保存しようとしているときに、マッパーがこのコレクションから変更されたドメイン オブジェクトのリストを取得できるようにする必要があります。

この場合のマッパーは、考えられるすべての条件でクエリを作成 (または事前設定されたものを使用) できる必要があります (開発者はこれらの条件をすべて知っているため、無限の条件セットで動作させる必要はありません)。コレクションに含まれる、保存されていないすべてのドメイン オブジェクトの新しいエントリを更新または作成します。

注:ある面では、マッパーはビルダー/ファクトリー パターンに関連していると言えます。目標は異なりますが、問題を解決するためのアプローチは非常に似ています。

于 2012-08-13T22:15:31.050 に答える
5

私は通常、次のようにこれをより具体的にすることを好みます。

BookDataMapper->getByAuthorAndPublisher($author, $publisher)

それは、SQL を再発明する必要がないからです。それにはデータベースの方が優れており、データマッパーはここで、アプリケーションの残りの部分が具体的にどのように保存またはクエリされるかについて何も知る必要がないことに注意します。

それをより動的にすると、インターフェイスを介して提供される機能が多すぎる傾向が簡単に生じます。良くない。

そして、あなたのアプリケーションを見てください。別の方法でクエリを実行することはそれほど多くないことがわかります。データの主要部分については、通常は約 5 ~ 10 のルーチンです。とにかく、実際にはそれ自体のレイヤーに属する動的システムについて考えるよりもはるかに速く書かれています。

于 2012-08-13T21:58:12.020 に答える