web-dev-qa-db-ja.com

単一の日付と日付範囲の両方を表すことができるプロパティ:適切にモデル化する方法は?

私は2つの方法で「送料見積もり」を表すことができるシステムで働いています。

  1. 特定の日付:アイテムはその日に出荷されることが保証されています
  2. 日間隔:アイテムは今日から「X to Y」日で発送されます

モデルの情報は意味的には同じで、「発送予定」です。配送見積もりの​​情報をシステムから取得すると、見積もりが最初の形式であるか2番目の形式であるかがわかります。

このための現在のモデルは次のようになります。

class EstimattedShippingDateDetails
{
    DateTime? EstimattedShippingDate {get; set;}
    Range? EstimattedShippingDayRange {get; set;}
}

Rangeは、整数の「始まり->終わり」をラップする単純なクラスで、次のようになります。

struct Range
{
    int Start {get; set}
    int End {get; set}

    public override ToString()
    {
        return String.Format("{0} - {1}", Start, End);
    }
}

推定モデルのプロパティの1つだけが入力されるため、このアプローチは好きではありません。一方のプロパティでnullをテストし、もう一方のプロパティにデータがあると仮定する必要があります。

各プロパティはユーザーには異なる方法で表示されますが、現在のスイッチングロジックが存在するカスタムMVC DisplayTemplateを使用して、UIの同じ場所に表示されます。

@Model EstimattedShippingDateDetails

@if (Model.EstimattedShippingDate.HasValue)
{
    Html.DisplayFor(m => Model.EstimattedShippingDate)
}
else
{
    Html.DisplayFor(m => Model.EstimattedShippingDayRange)
}

MVCアプリケーションで表示ロジックをシンプルに保ちながら、これをモデル化して実際の要件をよりよく表すにはどうすればよいですか?

インターフェースと、推定の「タイプ」ごとに1つずつ、2つの実装を使用することを考えましたが、両方の共通インターフェースに頭を抱えているようには見えません。メンバーなしでインターフェースを作成すると、統一された方法でデータにアクセスできなくなり、設計が良くありません。また、viewmodelをできるだけシンプルにしたかったのです。ただし、このアプローチでは「構築による修正」コードが得られます。これは、null値を指定する必要がなくなるためです。各実装には、n値を指定できないプロパティ(DateTimeまたはRange

単一のRangeのみを使用することも検討しました。状況#1が発生した場合、DateTimeStartの両方に同じEndを使用するだけですが、これにより値を比較して静的か間隔かを検出し、範囲を単一の日付またはフォーマットされた間隔として表示されるように適切にフォーマットする必要があるので、UIに値を出力する方法の複雑さ。

私が必要としているのは、TypeScriptの共用体に似た概念です。基本的には、2つの型のいずれかになるプロパティです。もちろん、C#にはそのようなものは存在しません(dynamicだけがそれに近いでしょう)。

8
julealgon

すべての配送見積もりには、日付範囲(2つの日付)を使用してください。

単一の日付の場合、XとYを等しくします。

17
Robert Harvey

カプセル化を使用してこれをモデル化できます。

クラスに2つのコンストラクターを持たせます。1つは単一の日付用、もう1つは日付範囲用です。

ToString()メソッドで、クラスの「状態」を判別し、適切なフォーマットされた文字列を生成します。

他のニーズに応じて、他のメソッドを追加します。

2
hocho

「開始」と「終了」はDateTimeではなく、オフセットです

MVCアプリケーションで表示ロジックをシンプルに保ちながら、実際の要件をよりよく表すためにこれをどのようにモデル化できますか?

「開始」と「終了」は、EstimatedShipDateへのオフセットです。それらはDateTimes自体ではありません。これにより、何が起こっているかがわかりやすくなり、複雑さが大幅に軽減されます。

interfaceは必要ありません。 Rangeクラスは必要ありません。必要なことが確実になるまで、複雑にしないでください。 3-optional-parameterコンストラクターを持つ単一のクラスが物事をずっと単純に保つと強く思います


サーバーから取得するデータは、配送予定日を表すDateTimeオブジェクト、または商品が配送される今日からの最小日数と最大日数の2つの整数値です。

1つのコンストラクタを使用してオプションのパラメータを介して3つの値すべてを渡します。これにより、必要なすべてのコンテキストが提供されます。 singleコンストラクタロジックは、すべてのバリエーションを評価して初期状態を正しく設定できます。また、必要に応じて、コンストラクター呼び出しで名前付きパラメーターを使用して、明確にする必要があります。

public class ShipDate {
    public ShipDate (Datetime? shipDate = null, int earliestOffset = 0, latestOffset = 0) {
        EstShipDate = (DateTime) shipDate ?? DateTime.Now.Date;
        start = earliestOffset < 0 ? 0 : earliestOffset;
        end   = latestOffset < 0 ? 0 : latestOffset;
        // That's all, folks!
    }
}

日付で標準化する場合、これらの整数を適切に構築されたDateTimeに変換する必要があります。

いいえ。これを行わないでください。物事はより簡単になります。代わりに、DateTime.AddDays() `を使用してください。

public DateTime EstShipDate      {get; protected set;}
public DateTime EarliestShipDate { get { return EstShipDate.AddDays(start).Date; } }
public DateTime LatestShipDate   { get { return EstShipDate.AddDays(end).Date; } }

日付とオフセット値の変更が許可されている場合、これはより柔軟になる可能性があります。


これは、クライアントとサーバーの日付、UTC、夏時間の差など、考慮に入れる必要があるすべてのもののために、かなり複雑さを引き起こします。この時点で、この種の複雑さを作成しないようにしたいと思います。

タイムゾーンの取り扱いについてはこちらをご覧ください。

今のところ、DateTime.DateTimeKind(列挙型)コンストラクターパラメーター。後で処理します。


答えの1つから:

2つの日付の正確なケースでは、朝から夕方までの日付範囲が最適なソリューションのようです。または、perhpasは開始日と整数の追加日数になる可能性がありますか?

使用 DateTime.Dateプロパティと時間を完全に無視します。

1
radarbob

これはかなり一般的な問題です。たとえば、Nullablesは、終了していないものに対するendDatesの一般的な問題を解決します。

しかし、あなたは悪い例を選んだと思います。

2つの日付の正確なケースでは、朝から夕方までの日付範囲が最適な解決策のようです。または、perhpasは開始日とそれがあるかもしれない余分な日数の整数ですか?

ただし、より難しいケースを考えてみましょう。配送方法は、ポストと店舗からの受け取りの2種類があります。これらははるかに異なるobvsであり、ショップには名前と住所が必要であり、ポストにはコストがかかり、おそらくいくつかの配送オプション、トラッキングコードなどがあります。

標準的なアプローチは、これらの「配信オプション」の両方を構成する共通のものを探し、それらを基本クラスに配置することです。 2つの特定のケースをサブクラス化し、必要な詳細情報を追加します。

ほとんどすべての場合、少なくとも1つのID、タイプ、および説明が両方のタイプに共通です。そう:

public class DeliveryOption 
{
     Public string Id;
     Public typeEnum Type;
     public string Description;
}


Public class Collection : DeliveryOption
{
     Public string ShopName;
}

Public class Post : DeliveryOption
{
     Public DateTime EstDelivery;
}
1
Ewan

のようなものはどうですか

_class EstimattedShippingDateDetails
{
    DateTime EarliestShippingDate {get; set;}
    DateTime LatestShippingDate {get; set;}
    TimeSpan Range 
    {
        get 
        { 
            return LatestShippingDate - EarliestShippingDate; 
        } 
    }
}
_

特定の日付:アイテムはその日付に出荷されることが保証されています

EarliestShippingDateLatestShippingDateの両方が保証配送日に設定されています。

日間隔:アイテムは今日から「X to Y」日で発送されます

EarliestShippingDateは今日に設定され、LatestShippingDatetoday + (Y - X)に設定されます

0
Spotted

単一の出荷日と1日で構成される範囲の違い(ある場合)を決定する必要があります。 「単一の出荷日」がたまたま1日で構成される場合は、すべてを開始日と終了日としてモデル化します。 「単一の出荷日」と、開始日と終了日が同じ日付の範囲を異なる方法で処理する場合は、2つのケースのいずれかを格納します。単一の出荷日の単一の日付と、日付の範囲の2つの日付。

0
gnasher729

基本的に2つのオプションがあります。

  • 2つの日付。オブジェクトが単一の日付を表す場合は、両方を同じ値に設定するか、2番目の日付をnull値に設定します。

  • 1つの日付とタイムスパン。日付は開始を表し、タイムスパンは範囲が将来どのくらいになるかを示します。単一の日付の範囲を0に設定します。

発送については、朝/夕方の配達をモデル化したいと思うので、日付ではなく日時を指定します。 2つのオプションのどちらが最適かは、表示の計算方法によって異なります。 「xとyの間」を表示している場合、最初のオプションの方が使いやすいかもしれません。「yから最大x日」を表示している場合、後者の方が使いやすいでしょう。

Null値が嫌いの場合は、後者のオプションの方が適しています。元の日付とタイムスパンの計算は、タイムスパンに値があるか0に設定されているかに関係なく実行できるためです。ヌルをチェックしなくても、常に正しい結果が得られます。

0
gbjbaanb