まず、私はこれを純粋に学術的な演習として求めています。 レポジトリパターンを使い続けるだけでとても満足しています。
「永続化メソッドをビジネスオブジェクトに配置するのは、ビジネスロジックの不可欠な部分だったので、永続化メソッドを配置した」と聞いたことがあります。これは、ビジネスオブジェクトにTimeToSaveイベント
ただし、永続化メソッドに戦略パターンを使用する場合、技術的にはドメインレイヤーに永続化ロジックを含めないことを主張することもできます。以下の例をご覧ください。
class MyEntity
{
private ISaveMyEntity _saver;
public MyEntity(ISaveMyEntity saver) { _saver = saver; }
public void Save()
{
_saver.Save(this);
}
//Real business methods
}
ビジネスオブジェクトに含めると、独自の永続化メソッドが便利です。さらに、ビジネスパターンがDTOになる一方で、リポジトリパターンは悪用されることが多く、CRUDだけでなくすべてのビジネスロジックが含まれることになります。私の意見では、これはCRUDメソッドを含むビジネスオブジェクトよりも悪いです。
戦略パターンを介してビジネスオブジェクトに永続性へのアクセスを含めることの潜在的な落とし穴は何でしょうか?戦略パターンを使用すると、ビジネスオブジェクトのストレージコードに一般的に関連するいくつかの問題が緩和されますか?
ビジネスルールを含む、ビジネスロジックを表す値オブジェクトを取得しました。次に、それらを永続化するメカニズムを追加します。けっこうだ。データベースを読み取ってデータベースから構築するメカニズムを追加してみませんか?おそらく、静的なLoad
メソッドがIGetMyEntity
インスタンスをパラメーターとして使用しますか?
あなたがそれをしている間、おそらくいくつかのメソッドを追加するのが最善です:
RenderAsHtml
、ToString
、ToJson
、ToXml
。これでどこへ行くのかわかる?それはすべて単純なSave
メソッドで始まりますが、いくつかのコミットは後でオブジェクトが突然すべてを認識し、凝集度が低く、すべてが単一の場所に詰め込まれ、不要なボイラープレートの残りをドラッグせずに再利用することは不可能ですそれ。
リポジトリー・パターンは拡張性が高いため、非常に一般的になりました。話しているオブジェクトが実際にビジネスルールのメモリ内表現であると想定されている場合、そのAPIの一部としてCRUDメソッドを含めることはできません。
DTOについてのあなたの意見を拡大するために、何らかの操作を行っているときに、ビジネスルールの検証が必要な場所はどこですか?読み取り中ですか?おそらくそうではない。一部のリソースへのアクセスを禁止することもできますが、それはビジネスルールというよりはむしろ承認の問題です。
ビジネスルールを適用する可能性が高い場所は、データがシステムに入力されるときです(完全に新しいものか、更新されたものか)。その場合、システムの状態を変更する操作が有効であることを確認する必要があります。実行される場合があります。このためには、制約を適用する値オブジェクトまたはエンティティを使用する必要があります。リポジトリは、実際にはビジネスロジックを格納する場所ではありません。リポジトリの目標は、ビジネスルールを適用することではなく、オブジェクトの永続性を抽象化することです。リポジトリに渡されるオブジェクトは、さらに処理するためにリポジトリに渡される前に、オブジェクト自体が有効であることを確認する必要があります。
また、リポジトリをすべてのCRUD操作を知っているクラスとしてではなく、アプリケーション内のレイヤーのように見ることをお勧めします。アプリケーションが大きくなると、読み取り時にエンティティの複数の表現が必要になる可能性があります。複数のGet*
メソッドを持つ単一のクラスとしてリポジトリがある場合、これは適切な感じではなく、クラスは非常に大きくなり、すぐに保守することが困難になる可能性があります-個人的な経験によるものです。
DTOが永続化に使用される理由はたくさんありますが、おそらく最も厄介なのはデータベーストランザクションです。 (つまり、複数のステップが必要であり、単一のきちんとしたUPDATE
、INSERT
、DELETE
などを実行できない場合)
トランザクションの基本的な要件のいくつかは次のとおりです。
COMMIT
は起こりませんROLLBACK
が発生してトランザクション全体が取り消され、データベースは以前の状態のままになります。部分的な更新や孤立したレコードはありません。アプリケーション内のビジネスオブジェクトを検討します。
次に、すべてのデータがデータベースからビジネスオブジェクトに直接取り込まれるシナリオを考えます。複数のクエリとUPDATE/INSERT/DELETEステートメントを必要とする可能性のある複雑なトランザクションをどのように実行しますか?
重要な問題は次のとおりです:ビジネスオブジェクトは一時的ではありません。それらにデータを追加すると、それらのdataが暗黙的にそれらの一部になりますstateそのデータをキャッシュしているため、キャッシュの存続期間はビジネスオブジェクトの存続期間と同じです。
結論-行動ドメインオブジェクトのlifetimeがデータベースに読み書きするオブジェクトの寿命を決定すると、コードの編成、トランザクションのロールバック、キャッシュの無効化、およびデータの同期の問題が発生します。
ダイアグラムが明確なビジネスオブジェクトでいっぱいになっていると「クリーン」に見えますが、それぞれが強力なIDを持ち、問題ドメインに簡単に関連付けられ、独自のデータと動作のすべてを1か所にカプセル化しますが、現実マルチオブジェクトの相互作用と、外部データベースでの永続データの管理の複雑さは、完全ではありません。
これにより、永続化が必要ない場合にオブジェクトを使用するのが不便になる可能性があると思われます。単体テストを行うには、永続化インターフェースをモックする必要があります。イベントベースのシステムでは、SaveMeイベントにサブスクライブしないことを選択できます。
別の潜在的な問題は、この方法で処理を行うと、効率的なバッチCRUD操作を実行する場合に、処理が困難になる可能性があることです。