2009-03-04 6 views
20

貧血ドメインモデルと懸念の分離に関するいくつかの質問を読んだことがあります。貧血ドメインオブジェクトでドメインロジックを実行/接続するための最善の手法は何ですか?私の仕事では、かなり貧弱なモデルがあります。現在、ドメイン・オブジェクトに対してデータベース/ビジネス・ロジックを実行するために、「ヘルパー」クラスを使用しています。たとえば、貧血ドメインモデルを扱う技術

購入する必要があるときは、StoreHelperを作成し、ドメインオブジェクトのメソッドを呼び出します。私にとっては、Customer/Productが自分自身をリポジトリに保存する方法を知っていることは理にかなっていますが、おそらくDomainオブジェクトにSave()メソッドを必要としません。また、Customer.Purchase(Product)のようなメソッドには意味がありますが、それはエンティティにドメインロジックを配置しています。

  1. 顧客と製品は一般的な方法で基本的なCRUD操作を提供し、「エンティティ」クラス(継承:

    ここ

    は、私が遭遇してきたいくつかのテクニックではなく、良い/悪いであることを確認していますおそらくORMを使用して)。

    • 長所:各データオブジェクトは、自動的にCRUD操作になるだろうが、その後データベース/ ORM
    • 短所に結ばれています。これは、オブジェクト上で、業務の問題を解決し、また、すべてのドメインオブジェクトを結び付けていませんそれは「純粋なデータベース」操作のためのDAO、および独立したビジネスヘルパーを持ってしても意味がないCRUD操作とビジネスロジック
      • を処理するために
    • 使用ヘルパークラスは適切でない可能性がありますベースのエンティティへ彼らのために鉱石事業特有の事業は?
    • このために非静的ヘルパークラスまたは静的ヘルパークラスを使用する方が良いですか?
    • 長所:ドメインオブジェクトは、任意のデータベース/ビジネスロジックに縛られていない(完全に貧血)
    • 短所:ない非常にOOではなく、非常に自然なアプリケーションコードでヘルパーを使用する(Cコードのように見える)
  2. (それが切り離されますが)エンティティが付属いくつかの余分なロジックを持っている
  3. :懸念
  4. 短所の良好な分離:エンティティは、任意のリポジトリに
    • の長所を保存するためのメソッドを持つダブルディスパッチ技術を使用してくださいC#3.0では
  5. 、あなたは
    • それに触れることなく、ドメインオブジェクトにCRUD /ビジネスメソッドを接続する拡張メソッドを使用することができ、これは有効なアプローチですか?賛否両論は何ですか?
  6. 他の手法はありますか?

これを処理するための最善の方法は何ですか?私はDDDにはかなり新しいです(私はエヴァンスの本を読んでいます - だから多分私の目を開くでしょう)

答えて

7

Martin Fowlerはanemic domain modelsを含むドメインモデルについて多くのことを書いています。また、役に立つドメインモデルやデータベースの多くのデザインパターンの簡単な説明(およびUMLクラス図)をCatalog of "Patterns of Enterprise Application Architecture"で紹介しています。

私はActive RecordData Mapperのパターンを調べることをお勧めします。問題の説明から、ヘルパークラスにドメイン/ビジネスルールのデータベース実装の詳細が含まれているようです。

アクティブレコードは、ヘルパーのドメインロジックとデータベースコードを(Entityベースクラスのような)他のドメインオブジェクトに移動します。データマッパーは、ヘルパーのドメインロジックをドメインオブジェクトに、データベースコードを別のマップオブジェクトに移動します。いずれのアプローチでも手続き型ヘルパークラスよりもオブジェクト指向になるでしょう。

Eric Evansの「Domain Driven Design」の本は優れています。それは少し乾くが、それは間違いなく価値がある。 InfoQには"Domain Driven Design Quickly" mini-bookがあります。これはEvansの本の紹介です。プラス "Domain Driven Design Quickly"は無料のPDFとして利用できます。

2

私は常に貧血ドメインモデルをアンチパターンと考えました。これは、顧客が製品を購入することは明らかだが、その能力は、その後必要に応じていることを実現することができ、インタフェースの実装

Interface IPurchase 
     Purchase(Product); 

して、ドメインオブジェクトのようにいずれかをgenerisedすることができます。このようにして、ドメインオブジェクトに機能を導入することができます。

14

あなたのヘルパークラスをリファクタリング、貧血のモデルを避けるために:

ロジックのような:
"Customer.PurchaseProduct(製品、製品、支払いの支払い)"、
「Customer.KillCustomer(人物キラー、武器兵器) "
は、" Customer "ドメインオブジェクトに正しく存在する必要があります。

ロジックのような:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
は、仕様に行く必要があります。

ロジックのような:
"Customer.Create()"、
"Customer.Update()"
は明らかにリポジトリに行く必要があります。

ロジックは次のように:
"Customer.SerializeInXml()"
"Customer.GetSerializedCustomerSizeInBytes()"
はサービスに行く必要があります。

複雑なコンストラクタは工場に行く必要があります。

それは私がそれを見る方法です。誰かがDDDのアプローチに関する私の理解をコメントすることができれば嬉しいです。


編集:たまに

- 貧血のドメインモデルshouldn't be avoided

私の答えを編集して、DDDはパターンの選択と削除に関するものではありません。
DDDは私たちの考え方です。

+0

お客様を扱うために、さまざまなクラスがたくさんあるようです。何かを複雑に扱うサービスで、大部分を単一のクラスに投げ捨ててみませんか? –

+0

私の答えは地獄のような古いです。 :D –

+0

@ LuckyLindy主にDDDはドメイン専門家とプログラマーの間の橋渡しをしているからです。ドメインモデルには技術的なものが含まれてはいけません。そうでなければ、普遍的な言語は存在できません。技術的なものを取り除くには、それを抽象化しなければなりません。何かを抽象化すると、コードベースが常に膨らみます。 –

0

あなたが言及していないアプローチの1つは、データアクセスを処理するためにAOPを使用することです。このアプローチの私の最近の使用例(投稿目的で大幅に簡素化されましたが)は、アカウントからの正常な口座引き落としを行うために必要なビジネスロジックをカプセル化して、debitメソッドを持つAccountドメインエンティティを持っていました。

N.B.すべてのコードは私の側面に注入し、適切なリポジトリと... AspectJのAOP表記で

public boolean debit(int amount) { 
    if (balance - amount >= 0) { 
     balance = balance - amount; 
     return true; 
    } 
    return false; 
} 

Javaのですが、私はその後、

pointcut debit(Account account,int amount) : 
    execution(boolean Account.debit(int)) && 
    args(amount) && 
    target(account); 

...このメソッドへの呼び出しをインターセプトするポイントカットを使用しました。 ..andいくつかのアドバイスを適用:私の意見では

after(Account account, int amount) returning (boolean result) : debit(account,amount) { 
    if (result) getAccountRepository().debit(account, amount); 
} 

を、これは懸念の素敵な分離を与え、あなたのドメインエンティティは、yのビジネスロジックに完全に集中することができます私たちのアプリケーション。

関連する問題