web-dev-qa-db-ja.com

状態パターンと継承

次の画像では、State PatternAppliing Domain-Driven Design and Patterns:With Examples in C#)および.NET

enter image description here

SalesOrderエンティティをデータベースに永続化しようとしています。通常、データベースにはsalesOrderテーブルがあり、フィールドcurrentStateはエンティティの現在の状態を示しています。

singleエンティティがあり、その状態には異なる動作しか含まれていないため、この実装は問題ありません。

ただし、異なる状態の他のプロパティを追跡する必要がある場合はどうなりますか?例:

  • SalesOrderがキャンセルされた場合、キャンセルされたquantitycancellationReasoncancelledBycancellationDateを追跡する必要があります。
  • SalesOrderが払い戻されると、refundQuantityrefundPricerefundFeeを追跡する必要があります。

つまり、基本的には、CancelledSalesOrderエンティティとRefundedSalesOrderエンティティに追加の属性があるようです。他の州についても同じことが言えます。

だから今の私の問題は、デザインを状態パターンの使用から継承の使用に変更しなければならないことです。ただし、継承では、実行時に状態を動的に変更できません(状態図が最初に解決する問題)。

だから私の質問:

  1. 各状態のエンティティに追加の属性がある場合、状態パターンは失敗しますか?代替は何ですか?
  2. この場合、エンティティを永続化するにはどうすればよいですか?単一テーブルの継承?クラスごとのテーブル?具体的なクラスごとのテーブル?
  3. 以前の状態のいくつかの属性を維持する必要がある場合(出荷済みの注文を払い戻しますが、出荷済みの状態から配送先住所を削除しないでください)、この問題にどのように対処しますか?
  4. どのようにして状態が発生した順序を追跡しますか?
4
Songo

いいえ、状態パターンは失敗しません。追加の「キャンセル」属性を「キャンセル済み」状態の一部にして、追加の「払い戻し」属性を「返金済み」状態の一部にしてください(図で後者の状態を忘れてしまったと思いますか?)

「状態」エンティティはSalesOrderの集合体であるため、「状態」の属性はSalesOrderへの「詳細の追加」としてのみ見ることができます。

OrderState階層にどの種類の継承マッピングを選択するかは、実際には問題になりません。通常の3つはどれでも機能します。

状態パターンを使用すると、後で状態が変化した場合でも、以前の状態の属性を保持できます。たとえば、状態が「発送済み」から「請求済み」に変わっても、「配送先住所」を保持する必要がある場合があります。これは、一度に複数の状態を許可することで解決できます。SalesOrderとOrderStateの関係を「1:1」ではなく「1:n」にするだけです。したがって、「状態を出荷済みから請求済みに変更する」のではなく、「請求済み」の状態を事前に削除せずに、「請求済み」という追加の状態を「StateOrder」エンティティに追加します。もちろん、このモデルを使用して、発送されるすべての注文を探す場合、「付与」された注文だけでなく、「付与されたがまだ発送されていない注文」もチェックする必要があります。ただし、これは処理の詳細にすぎず、処理が難しくなりすぎてはなりません。

複数の状態を持つことは、実際の状況をより適切に反映するので、IMHOは「より良い」モデルです。たとえば、発送して請求したものは、「請求済みおよび出荷済み」ではなく、「出荷済みおよび請求済み」です。

2
Doc Brown