ビューモデルでのビジネスオブジェクトの使用


11

再利用可能なビジネスオブジェクトを使用する場合、ビューモデルを構築する際のベストプラクティスとは何ですか?

呼び出すオブジェクトを使用して、Builderビューモデルを構築します。ビューの各論理ユニット(オーダー、ユーザーなど)ごとに1つのビルダー。ここで、各ユニットにはさまざまなビューモデルを含めることができます(オーダーにはサマリー、オーダーラインなどが含まれます)。

ビルダーは、ビューモデルを構築するために、1つ以上の標準ビジネスオブジェクトを介してデータをプルする場合があります。

ビューモデルでビジネスオブジェクト/モデルを使用する場合のベストプラクティスとは何ですか?

アプローチ1

ビューモデルでビジネスオブジェクトの使用を許可しますか?

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary();
        obModel.Order = obOrder;

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public Some.Business.Logic.Order Order;
    //Other methods for additional logic based on the order
    //and other properties
}

アプローチ2

ビジネスオブジェクトから必要なデータのみを取得する

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary()
        {
            OrderNum = obOrder.OrderNum,
            NumOrderLnes = obOrder.NumOrderLines,
        }

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public int OrderNum;
    public int NumOrderLines
    //Other methods for additional logic based on the order
    //and other properties
}

私は両方の利点と欠点を見ることができますが、受け入れられたアプローチがあるのだろうか?アプローチ1では、モデルの周りにコードの重複はありませんが、ビジネスロジックへの依存関係を作成します。アプローチ2では、ビューに必要なデータのみを取得しますが、モデルの周りにコードを複製します。

回答:


12

オプション1は、ドメインモデルとビューの間に密結合を作成します。これは、モデルが解決するように設計されているビューの問題に反します。

ビューモデルが「変更する理由」は、ビュー自体が変更された場合です。ビューモデルにドメインモデルオブジェクトを配置することで、変更する別の理由を導入しています(たとえば、ドメインが変更された)。これは、単一責任原則の違反を明確に示しています。変更する2つ以上の理由があると、多くのメンテナンスを必要とするビューモデルにつながります。おそらく、ドメイン/ビューモデル間での複製のメンテナンスコストよりも多いでしょう。

私は常にアプローチ2を提唱します。ビューモデルはドメインモデルオブジェクトと非常によく似ている場合がありますが、ドメインモデルオブジェクトと同じである場合もよくあります。


「変更する理由」とは、更新(UIイベントなど)の意味での変更ではなく、保守の意味での変更を意味すると思いますか?
アンディハント

@AndyBurshそうですね- この記事、特に「Robert C. Martinは責任を変更の理由として定義し、クラスまたはモジュールには1つだけの変更理由が必要だと結論付けています」
-MattDavey

私はあなたの答えが好きですが、いくつかの考え...ビューモデルは、モデルが変わったからといって必ずしも変わるわけではありません。参照するのはオブジェクト全体であるため、バインドまたは変更された特定のプロパティを使用している場合にのみこれが問題になります。ドメインオブジェクトへの参照があると、変更を加えて保存しやすくなります。保存メソッドもドメインオブジェクトに依存しているため、ビューモデルを元に戻すか、ビジネスメソッドをセットアップして、ビューモデルも受け入れられないようにする必要があります。私はまだ#2が最も理にかなっていると思いますが、わずか2セントです。
KingOfHypocrites

VMにドメインオブジェクトを含めることができない場合、注文の配列のようなより複雑なものをどのように表現しますか?
ジェフ

これは、たとえば、ユーザー表示用のタイムスタンプのフォーマットなど、ドメインレイヤーではなくビューレイヤーに属し、ドメインレベルのオブジェクトが未フォーマットの未フォーマットのタイムスタンプのみをビューオブジェクトに返すことを意味します。フォーマッタロジックが含まれていますか?
The_Sympathizer

2

コードの重複を避けるため、オプション1をお勧めします。それでおしまい。

ドメインモデルが大幅に変更された場合、ビューを変更する必要があることはほぼ確実です。オプション2では、ビューモデルとビルダー、およびビュー自体を変更する必要があります。そのようなことは、保守性にとって絶対的な毒です。ヤグニ。

別のビューモデルを持つことのポイントは、ビジネスモデルとは別に、ビューでのみ意味のある状態(現在選択されているタブなど)を保持することです。ただし、ビジネスデータ自体は複製するのではなく、再利用する必要があります。


YAGNI-ほとんどのソフトウェア設計問題を解決する秘密の暗殺者。
マーティンブロア

6
申し訳ありませんが、これは最も些細なアプリケーションを除くすべてにとって恐ろしいアドバイスです。ビューモデルには状態がありません。これらはデータ転送オブジェクトです。どのタブが選択されるかは、ビューの構造の一部であり、ビューモデル内のデータとは関係ありません。プログラムを適切に構成し、Automapperなどを使用してビューモデルをハイドレイトすると、メンテナンスは悪夢ではありません。
ルシファーサム

「ドメインモデルが大幅に変更された場合、ビューを変更する必要があることはほぼ確実です。」-同意した。しかし、ドメインに小さな変更がある場合はどうでしょうか?オプション1を使用すると、ドメインの小さな変更ごとに(プロパティの名前を変更するだけでも)ビューに対応する変更が必要になります。これは保守性にとっても絶対的な毒です。
MattDavey

@MattDavey:プロパティの名前を変更し、別のビューモデルを使用する場合は、ビュー(またはドメインとビューモデルの間のマップ)も変更する必要があり、同じものに対して2つの異なる名前を付ける必要があります。
マイケルボルグワード

@Lucifer Sam:明らかに、ビューモデルとは何かという非常に異なる概念を持っています。ダム端末用のメインフレームアプリについて説明しているように見えますが、確かに最新のWebアプリやファットクライアントアプリではありません。
マイケルボルグワード

2

原則とマントラは、デザインを導くために時々貴重です...しかし、ここに私の実用的な答えがあります:

ビューモデルがJSONまたはXMLにシリアル化されることを想像してください。ドメインモデルをシリアル化しようとすると、テキストの恐ろしい混乱に陥り、循環参照やその他の問題が発生する可能性が高くなります。

ビューモデルの目的は、ドメインモデルをグループ化してビューがそれらを消費できるようにすることではありません。代わりに、ビューモデルはビューの完全にフラットなモデルである必要があります...画面上で実際に見ているものです。ビューロジックは、ビューモデルに存在するデータの構造化にのみ関係する必要があります。

理想的には、ビューモデルはほぼ完全に事前にフォーマットされた文字列で構成される必要があります。考えてみてください。C#、Javascript、Objective-Cなどでフォーマットロジックを実行するのにこだわっているので、ビューモデルにDateTimeや小数も必要ありません。


2
ドメインモデルのシリアル化で問題が発生したことはありません。そして、モデル内のすべてを文字列に変換しますか?マジ?
マイケルボルグワード

3
@MichaelBorgwardtはい、これがビューモデルです。ドメインモデルをシリアル化し、あちこちに送信したくありません。すべてのビジネスロジックは、1つの場所で安全に自宅に滞在する必要があります。ただし、ビューは柔軟性があり、どのデバイスでもレンダリングできる必要があるため、構造、データ、スタイルを完全に分離する必要があります。
ルシファーサム

申し訳ありませんが、それはあらゆるアプリケーション、期間に対する恐ろしいアドバイスです。これは、柔軟性とは正反対の重複コードでいっぱいの過剰設計されたアプリケーションにつながります。
マイケルボルグワード

1
@MichaelBorgwardtエンティティがほとんどまたはまったく動作のないプロパティバッグに過ぎない貧弱なドメインモデルで作業することに慣れているように聞こえます。その場合、はい、DTO / View-modelは基本的に重複します。ただし、複雑な関係を持つリッチドメインモデルがある場合は、DTO /ビューモデルのレイヤーが必要になり、それらはドメインエンティティにあまり似ていません。
MattDavey

@MattDavey:作業に慣れているドメインモデルは、金持ちだけでなく真正なクレプトクラトのようです。私は貧血モデルも好きではありませんが、それらはまだモデルであり、それらの振る舞いはドメインを表すことに限定されるべきです。単一責任の原則とすべてのこと...
マイケルBorgwardt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.