AdventureWorksをモデリングしてDDDしながらドメインモデルで実装してみる(12)

販売注文エンティティの責務を分解して整理する

販売注文はイベント(トランザクション)系のエンティティです。対応するテーブルには状態値や区分や種類が含まれています。これらを責務を識別して分離することで1クラス1責務に近づけて安定化します。

まずStatusがオブジェクトの状態を表しているのでサブクラスで表現しました。実装時に継承で実装するかは別ですが、サブクラスで表現することで特定の状態時に設定される項目を表現可能になります。今回、出荷日(ShipDate)がNULL可になっており、出荷時に設定されると推測されます。なお、状態を持っているエンティティは対応するイベントがあり、そのイベントが発生して状態変化します。したがって、承認イベントやバックオーダーイベントが推測され、さらにイベントを引き起こす操作として承認やバックオーダーの操作が想像できます。
OnlineOrderFlagとAcoountNumberは販売注文エンティティの種類や財務的な分類を表しています。これは販売注文を説明する情報と考えることができます。
PurchaseOrderNumberは顧客発注情報をあらわしています。現時点ではIDだけの管理のようですがここでは顧客発注イベントとして考えることができます。また、顧客関係の情報をまとめて発注顧客としました。発注顧客は販売注文から見た顧客の責務をあらわしたもので、特定の役割になるためロールとして分類しています。同様に販売クレジットカードは単なるカード情報だけではなくクレジットの責務ももつ意図で承認コードと合わせて管理させます。販売輸送会社も同様です。

サービス・ポリシーパターンの利用

続いてTaxAmt消費税の計算結果ですが、消費税計算は販売区域の税率などの情報をもとに算出されるので消費税(SalesTaxRate)に持たせれば良いのですが、販売注文から直接ナビゲーションできません。販売区域経由にナビゲーションするアイデアもありますが、販売区域と消費税に強い結びつきを前提にするのは少し違和感があります。したがって、ここではルックアップする仕組みを利用します。消費税を計算するルールを消費税計算サービスとしてルックアップできるようにします。このとき販売区域をルックアップのパラメータすなわち消費税計算ポリシーとしてあつかうようにすることで結びつきが緩やかなものにしました。

このようにサービスを仮想してポリシーベースのルックアップメカニズムを導入すると、変化に柔軟に対応可能なビジネスルールを実装することができます。

エンティティのロール化による責務の分割

明細については、まずCarrierTrackingNumberが外部システムの配送イベントを示唆しています。また販売された製品については、値引き情報を含めて管理しており販売製品として製品のロールとして考えました。

今回何度もでてきたロールですが、ここでは相互作用する相手側のエンティティの振る舞いをラップ(理想化)することで自エンティティの複雑さを低減することを狙います。関連エンティティがあれば機械的に導入できるので簡単にエンティティを分解することができます。今回分析段階ではロールを多用していますが、実装時に必要なければ削除することになります。