web-dev-qa-db-ja.com

ビジネスオブジェクト-コンテナまたは機能?

これは私がしばらくSOに戻って尋ねた質問ですが、ここでよりよく議論されるかもしれません...

私が働いている場所では、この問題について何度も行ったり来たりして、健全性チェックを探しています。ここに質問があります:ビジネスオブジェクトはデータコンテナー(もっと DTOs のようなもの)であるか、またはそのオブジェクトでいくつかの機能を実行できるロジックを含んでいる必要がありますか?.

例-カスタマーオブジェクトを取得します。これにはおそらくいくつかの一般的なプロパティ(名前、IDなど)が含まれますが、そのカスタマーオブジェクトには関数(保存、計算など)も含める必要がありますか?

推論の1行は、オブジェクトを機能(単一の責任主体)から分離し、機能をビジネスロジックレイヤーまたはオブジェクトに配置することを示しています。

もう1つの推論の行は、いいえ、もし私がCustomerオブジェクトを持っているなら、Customer.Saveを呼び出してそれで終了したいだけです。オブジェクトを使用している場合、顧客を救うために別のクラスについて知る必要があるのはなぜですか?

私たちの最後の2つのプロジェクトでは、機能から分離されたオブジェクトがありましたが、議論は新しいプロジェクトで再び提起されました。

どちらがより理にかなっており、なぜですか?

19
Walter

Customerがドメインモデルの一部であると考える場合、そのオブジェクトのプロパティと操作の両方を持つことは(特にDDDのコンテキスト内であるが、それに限定されない)意味があります。

しかし、そうは言っても、あなたが使用した例は貧弱なものであり、議論の原因であると私は思います。持続性について話している場合、顧客は通常、自分自身を「保存」しません。永続化のために使用しているものは何でも。あらゆる種類の永続性が永続性レイヤー/パーティションに属している必要があることは理にかなっています。これは通常、リポジトリパターンの背後にある考え方です。** Customer.UpgradeWarranty()またはCustomer.PromoteToPreferred()などのメソッドは、引数をより明確にします。

これは DTO の可能性も排除しません。たとえば、顧客情報をリモートサービスに渡す場合を考えてみましょう。顧客が転送用にそれ自体のDTOを作成することは意味がないかもしれませんが、それはアーキテクチャ上の問題ですが、永続化またはネットワークレイヤー/パーティション/コード/ what-have-youでケースが作成される場合があります。その場合、そのようなオブジェクトは次のようなメソッドを持つことができます

public static CustomerDTO GetDTO(Customer c) { /* ... */ }

public static Customer GetCustomer(CustomerDTO cdto) { /* ... */ }

したがって、要約すると、ドメイン内の論理操作と一致するドメインオブジェクトの操作を行うことは完全に理にかなっています。

問題についての多くの良い議論のための「永続性無知」のためのグーグル( これSO質問 、そしてその受け入れられた答えは始めるのに良い場所です)。

**これは、「保存」メソッドを持つ永続的なベースからの継承を強制される特定のOR/Mソフトウェアで少し混乱します。

5
Steven Evers

どちらの方法でもメリットがあると思いますが、オブジェクト指向またはドメイン主導の観点から見ていきます。さまざまなクラスとオブジェクトの責任は何ですか。

それで、あなたの具体的なケースでは、私はこれを自問します:顧客は自分自身を保存する方法を知っているべきですか?

私にとっての答えは「いいえ」です。論理的にはそれは意味をなさず、顧客は永続フレームワークについて何も知る必要がないはずです(責任の分離)。

Customer.UpgradeWarranty()またはCustomer.PromoteToPreferred()を使用したSnOrfusの例は、Customer.Save()よりも明らかにビジネスロジック指向です。これにはさまざまなアプローチがありますが、お客様が保証をアップグレードできるかどうかを自問すると、答えは、見方に応じて「はい」または「いいえ」になります。

  • はい:お客様はもちろん保証をアップグレードできます
  • いいえ:顧客はアップグレードすることができますaskですが、アップグレードは他の誰かによって行われます

元の質問に戻ります。どちらの方法がより理にかなっているかは、おそらくあなたが尋ねた人と彼らの好ましい方法に依存するでしょうが、最も重要なことは、おそらくそれを行う1つの方法に固執することです。

しかし、私の経験では、データと(ビジネス)ロジックを分離すると、それほど刺激的ではありませんが、より単純なアーキテクチャになります。

3
Vetle

実際、私は最近、オブジェクトをデータから分離するためにいくつかのコードを作り直しました。その理由は、データが別のサービスを介して取得されるため、オブジェクト全体をやり取りしてサーバーで検証エラーを処理する必要がなく、生のデータをサーバーとの間でやり取りする方がはるかに簡単です。

小さなプロジェクトの場合、オブジェクトにビジネスロジックとデータを含めることはおそらく問題ありませんが、大規模なプロジェクト、または時間とともに拡大する可能性のあるプロジェクトの場合、レイヤーを確実に分離します。

3
Rachel

ActiveRecordパターンとRepositoryパターンの違いについて具体的に話していると思います。前者の場合、エンティティは自分自身を永続化する方法を知っており、後者の場合、リポジトリは永続性について知っています。後者の方が懸念の分離が良いと思います。

広い意味では、エンティティがデータ構造のように振る舞う場合、それらは振る舞いを持つべきではありませんが、振る舞いがある場合、それらはデータ構造のように使用されるべきではありません。例:

データ構造:

class CustomerController
{
    public int MostRecentOrderLines(Customer customer)
    {
        var o = (from order in customer.Orders
                orderby order.OrderDate desc
                select order).First();
        return o.OrderLines.ToList().Count;
    }
}

非データ構造:

class Customer
{
    public int MostRecentOrderLines()
    {
        // ... same ...
    }
}

最初のケースでは、作業コード内のどこからでも問題なくモデルのデータ構造ツリーをナビゲートできます。データ構造のように扱っているため、問題ありません。後者の場合、Customerは特定の顧客に対するサービスに似ているため、結果に対してメソッドを呼び出さないでください。 Customerオブジェクトでメソッドを呼び出すことにより、Customerについて知りたいすべてのものが利用可能になります。

エンティティをデータ構造またはサービスにしたいですか?一貫性を保つために、1つに固執する方が良いようです。前者の場合、「サービス」タイプのロジックをエンティティではなく別の場所に配置します。

2
Scott Whitlock

答えは、実際にはアーキテクチャ/デザインに依存します。ドメインモデルを使用したDDDアーキテクチャは、オブジェクトデザインに関して、CRUDデータ中心のモデルとは大きく異なります。

ただし、一般に、オブジェクト指向設計では、状態をカプセル化して動作を公開しようとしていることに注意してください。これは通常、動作に関連付けられた状態をできるだけその動作に近づけようとすることを意味します。これに失敗すると、何らかの形で状態を公開することを強制されます。

ドメインモデルでは、ビジネスモデルをインフラストラクチャの問題から分離したいので、 '。Save'のようなメソッドは絶対に避けたいです。私が実際に顧客を最後に「保存」したのを覚えていません!

CRUDアプリケーションでは、データは一級市民であるため、「。Save」が完全に適切です。

ほとんどのかなり現実的なアプリケーションには、これらのパラダイムが混在します-急速に変化するまたは複雑なビジネスルールが存在するドメインモデル、境界を越えてデータを転送するためのDTO、CRUD(またはCRUDとActiveRecordなどのドメインモデルの間の何か)。万能のルールはありません。

1
FinnNk

私は本当にあなたの質問に答えることはできませんが、学校での私たちのプロジェクトの1つでもこの議論をしているのは面白いと思います。私はロジックをデータから分離したいと思います。しかし、私のクラスメートの多くは、オブジェクトはすべての論理ANDデータを保持する必要があると言っています。

私が彼らが持ち出す事実を要約してみましょう:

  • ビジネスクラスオブジェクトはモノを表すため、すべてのデータとロジックを含める必要があります。 (例えば、あなたがドアを開けたいなら、あなたは自分でそれをします、あなたは誰かに尋ねません。悪い例は私が知っています)

  • Buオブジェクトのコードと機能を理解しやすくなりました。

  • 設計の複雑さを軽減

私は彼らが怠惰であることを彼らに言っています、そして私はこのようにします:

  • はい、ビジネスクラスは物事を表すので、データを保持します。しかし、自分自身を保存したり、コピーしたりするのは間違っていると感じています。 rlではできません。

  • オブジェクトにすべての責任を持たせることは、将来の耐久性や保守性に悪影響を及ぼします。保存を担当する別のクラスがある場合、新しいオブジェクトをデザインに追加すると、その保存機能を簡単に実装できます。そのクラスですべてをもう一度コーディングする代わりに。

  • 1つのオブジェクトがデータを永続化できるようにすることで、そのオブジェクトはデータベース接続を保持でき、すべてのデータベーストラフィックがそのオブジェクトで誘導されます。 (基本的にそのデータアクセスレイヤー)そうでない場合、すべてのBusinessオブジェクトは接続を保持する必要があります。 (これにより複雑さが増します)

どういうわけか、私は先生に尋ねるつもりです。私がそれをしたとき、もしよろしければ彼の答えもここに投稿します。 ;)

編集:

このプロジェクトが書店に関するものであることを言及するのを忘れていました。

1
Emerion

私はしばらくの間、同じ質問について検討してきました-データコンポーネントとロジックコンポーネントは分離している必要があると思います。これは、ビジネスロジックを意味を提供するデータへのインターフェースと見なすという正しい考え方にたどり着くためです。

また、スコットウィットロックのポイントを上から変更します(新しいメンバーになるポイントがないことを除きます)。データやビジネスロジックのクラスは、オブジェクトが永続的に格納される方法について心配する必要はありません。

そうは言っても、既存の製品を扱っているのであれば、契約に基づいたクリーンなインターフェースがある限り、それも問題なく、保守可能です...

0
heretik