オブジェクトの境界を越えて流出する情報


10

多くの場合、私のビジネスオブジェクトは、情報がオブジェクトの境界を頻繁に越える必要がある状況にあります。オブジェクト指向を実行するときは、情報を1つのオブジェクトに入れ、その情報を処理するすべてのコードをできるだけそのオブジェクトに含める必要があります。ただし、ビジネスルールはこの原則に従っていないため、問題が発生します。

例として、価格を持つInventoryItemを参照するOrderItemの数を持つOrderがあるとします。数量をInventoryItem.GetPrice()で乗算するOrderItem.GetPrice()の結果を合計するOrder.GetTotal()を呼び出します。ここまでは順調ですね。

しかし、その後、一部の商品が2対1で販売されていることがわかりました。OrderItem.GetPrice()にInventoryItem.GetPrice(quantity)のような処理を行わせ、InventoryItemにこれを処理させることで、これを処理できます。

ただし、2対1の取引は特定の期間のみ続くことがわかります。この期間は、注文の日付に基づく必要があります。次にOrderItem.GetPrice()をInventoryItem.GetPrice(quatity、order.GetDate())に変更します。

ただし、お客様がシステムに滞在している期間に応じて、さまざまな価格をサポートする必要があります。

しかし、2対1の取引は、同じ在庫アイテムを複数購入するだけでなく、InventoryCategory内のアイテムの複数購入にも適用されることがわかります。この時点で、私たちは手を挙げて、InventoryItemに注文アイテムを与え、それがアクセサーを介してオブジェクト参照グラフ上を移動できるようにし、必要な情報を取得します:InventoryItem.GetPrice(this)

TL; DRオブジェクトの結合を低くしたいのですが、ビジネスルールでは、特定の決定を行うために、多くの場合、どこからでも情報にアクセスする必要があります。

これに対処するための良いテクニックはありますか?他の人が同じ問題を見つけますか?


4
一見すると、InventoryItemクラスが価格を計算することであまりにも多くのことを試みているように思われ、特定の価格を返すことは1つのことですが、セール価格と特別なビジネスルールはInventoryItemのアドレスではありません。価格を計算するためのクラスを展開し、注文、在庫、顧客などからのデータの必要性を処理できるようにします。
Chris

@クリス、はい、価格設定ロジックを分割することはおそらく良い考えです。私の問題は、そのようなオブジェクトが注文に関連するすべてのオブジェクトに密結合されることです。それが私を悩ませている部分であり、私が回避できるかどうか疑問に思っている部分です。
Winston Ewert、2011年

1
もし何か、私はそれを何とも呼ばないで、その情報のすべてを必要とするなら、どういうわけかそれは望ましい情報を生み出すためにこの情報を消費しなければなりません。在庫、アイテム、顧客などがすでに構築されている場合は、独自の領域にビジネスロジックを実装することが最も理にかなっています。本当に良い解決策はありません。
Chris

回答:


6

私たちが働いているのと基本的に同じ経験があり、OrderBusinessLogicクラスを持つことでそれに対処しました。あなたが説明したレイアウトの大部分は、私たちのビジネスの大部分で機能します。それは素晴らしく、清潔でシンプルです。ただし、このカテゴリから2つを購入した場合は、それを「ビジネス例外」として扱い、OrderBLクラスに必要なオブジェクトをたどって合計を再計算させます。

いいえ、それは完璧な解決策ですか?まだ1つのクラスが他のクラスについてあまりにも多くのことを知っていますが、少なくともその必要性をビジネスオブジェクトからビジネスロジッククラスに移動しました。


2
疑わしい場合は、別のクラスを追加してください。
Chris

1

あなたのようなサウンドは、すべてのものを追跡し、個別のディスカウントオブジェクト(またはそれらのリスト)を必要とし、その後何かのように、注文にディスカウント(複数可)を適用するOrder.getTotal(Discount)か、Discount.applyTo(Order)または類似しました。


Inventoryオブジェクトではなく、Discountにコードを配置した方が良い場合があることがわかります。しかし、割引オブジェクトは、その仕事を完了するために、すべての異なるオブジェクトの情報にアクセスする必要があるようです。したがって、少なくとも私が見る限りでは、問題は解決しません。
Winston Ewert、2011年

2
ディスカウントオブジェクトは良いアイデアだと思いますが、オブザーバーパターン(en.wikipedia.org/wiki/Observer_pattern)を実装し、ディスカウントをパターンの主題として
BlackICE

1

他のクラスのデータにアクセスしても問題ありません。ただし、これを一方向の関係にする必要があります。たとえば、ClassOrderがCallItemにアクセスするとします。理想的には、ClassItemはClassOrderにアクセスすべきではありません。注文クラスで欠けていると思うのは、ウォルターが提案するようなクラスを保証するかどうかわからない、ある種のビジネスロジックです。

編集:ウィンストンのコメントへの応答

私はあなたがインベントリアイテムオブジェクトをまったく必要としないと思います...少なくともあなたがそれを使用している方法で。代わりに、在庫データベースを管理する在庫クラスがあります。

在庫品はIDで参照します。各注文には、在庫IDのリストと対応する数量が含まれます。

それから私はこのようなもので注文の合計を計算します。
Inventory.GetCost(Items、customerName、date)

次に、次のような他のヘルパー関数を使用できます。

Inventory.ItemsLefts(int itemID)
Inventory.AddItem(int itemID、int数量)
Inventory.RemoveItem(int itemID、int数量)
Inventory.AddBusinessRule(...)
Inventory.DeleteBusinessRule(...)


密接に関連するクラスからのデータを要求することは完全に問題ありません。この問題は、間接的に関連するクラスのデータにアクセスしているときに発生します。そのロジックをOrderクラスに実装するには、OrderクラスがInventoryオブジェクト(必要な価格設定データを含む)を直接処理する必要があります。Orderを(理想的には)何も知らないクラスに結合しているので、これは私を悩ませている部分です。
Winston Ewert、2011年

基本的に、あなたのアイデアはOrderItemを排除することです。代わりに、Orderはそのすべての情報自体を追跡します。その後、その情報を価格情報の別のオブジェクトに渡すのは簡単です。それはうまくいくかもしれません。(特定のシナリオでは、この例はOrderItemに大まかに基づいており、複雑すぎたため、実際には独自のオブジェクトである必要がありました)
Winston Ewert

私にとって意味をなさないのは、オブジェクト参照ではなくID番号を使用してインベントリを参照させたい理由です。オブジェクトの参照と数量を追跡し、次にアイテムIDと参照を追跡する方が私にはずっと良いようです。
Winston Ewert、2011年

私はそれをまったく提案していません。注文アイテムのクラスまたは構造がまだあるはずだと思います。個々のインベントリアイテムオブジェクトは内部に価格を持つべきだとは思いません。主に、データベースの種類を尋ねずにどのように取得するかわからないからです。注文または在庫アイテムは、厳密にはアイテム識別子と数量を含むデータクラスです。注文自体には、これらのオブジェクトのリストがあります。
Pemdas、2011年

2番目のコメントであなたが何を求めているのか本当にわかりません。すべてがオブジェクトである必要はありません。なんらかのIDなしで特定のアイテムをどのように見つけるのか本当にわかりません。
Pemdas、2011年

0

これについてもっと考えた後、私は自分自身の代替戦略を考え出しました。

Priceクラスを定義します。Inventory.GetPrice()価格オブジェクトを返します

Price OrderItem::GetPrice()
{
    return inventory.GetPrice().quantity(quantity);
}

Currency OrderItem::GetTotal()
{
    Price price = empty_price();
    for(item in order_items)
    {
         price = price.combine( item.GetPrice() )
    }
    price = price.date(date).customer(customer);
    return price.GetActualPrice();
}

現在、Priceクラス(および場合によってはいくつかの関連クラス)は、価格設定のロジックをカプセル化しており、注文はそれについて心配する必要がありません。PriceはOrder / OrderItemについて何も知らず、代わりに単に情報が入力されるだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.