割引モデルに適用される設計パターンはありますか?


35

割引モデルを実装するための既知の設計パターンはありますか?

割引モデルとは、次のことを意味します。

  1. 顧客が製品X、製品Y、および製品Zを購入すると、10%または100ドルの割引を受けます。

  2. 顧客が製品Xを100単位購入すると、15%または$ 500の割引を受ける

  3. 顧客が昨年に10万ドル以上持ち込んだ場合、20%の割引が適用されます

  4. 顧客が製品Xを2ユニット購入した場合、製品X(または製品Y)を1ユニット無料で入手できます。

  5. ...

上記のすべてのシナリオを処理するために適用できる一般的なパターンはありますか?私はいくつかのモデルを考えていますが、一般的なモデルに出くわすことはできません。


IIRC私は割引を伴う例で見てきたすべてのチュートリアル(多くがある)Strategyパターンを示唆
ブヨ

2
@Kaniniこれは現実の問題ですか?そのような場合、このシステムはリアルタイムですか、それとも遅延ですか?これらのルールはルールエンジンまたはデータベースの値として提示されていますか?割引の検索は優先度に基づいて階層化されていますか?ほとんどの場合、戦略パターンは機能しますが、ルールを考慮して機能させる必要があります
-Ubermensch

3
また、誰かが製品Xを2ユニット、製品Yを1つ、製品Zを1つ購入すると、10%と追加の製品Xの両方が得られますか?
-Ubermensch

@gnatこれらのチュートリアルのいくつかへのリンクをお願いします。
user16764

回答:


18

特定の状況下で複数の割引を適用する必要があるという問題がある場合は、責任連鎖パターンを検討することをお勧めします。

簡単に言うと、処理する情報を最初のプロセッサに渡し、そこから結果を返す前に他のプロセッサに渡すかどうかを決定します。

これにより、呼び出しコードを変更することなく、プロセッサの構造とシーケンスを変更できます。


責任の連鎖もまた良いものです。戦略と結び付けられることさえあります。1つの割引のみを適用できる場合、各戦略は別の戦略と連鎖します。各チェーンは割引を計算し(顧客が資格がある場合)、以前の割引と比較し、顧客、注文、割引のデータを次のチェーンに渡します。+1。
トーマスオーエンズ

1
ただ私の意見ですが、このケースでは「責任の連鎖」が過剰に設計されている可能性が高いと思います。割引モデルの単純なリスト(必要に応じて、注文番号を使用)でそれを行う必要があります。すべての顧客は平等に扱われるため、リスト自体は顧客と彼の注文から独立しています。「責任の連鎖」は、実行時にディスカウントモデルリストが非常に動的な方法で非常に頻繁に変更される場合により適しています。
Doc Brown

11

戦略、デコレーター、および状態のパターンは、潜在的な出発点として際立っています。2は注文の状態に依存し、3は一定期間内の顧客の状態に依存するため、状態は2または3に特に役立ちます。Strategyを使用して複数の注文価格計算アルゴリズムとデコレータを実装し、注文に新しい割引を追加できるため、Strategy and Decoratorは他の製品よりも優れています。

ただし、設計パターンは単なるモデルであることを忘れないでください。適用される単一のパターンではなく、パターンのシステムがある場合があります。また、記述されたモデルを修正して、ソリューションにより適合させることを検討してください。パターンがあると言うことができるためだけに役立つとは限らないパターンを強制するよりも、良いデザインを持つ方が良いです。


しかし、それは実際には状態パターンが意図していることではありません。
pdr

@pdrなぜそうなのかわかりません。ただし、実装によって異なります。顧客オブジェクトが顧客依存の割引を追跡する場合、顧客が適格な割引を返す操作が存在する可能性があります。顧客が物を購入すると、属性が変化し、このメソッドの実装は状態パターンを介して変化します。
トーマスオーエンズ

1
うーん、どういう意味かわかります。顧客がアプリケーション内の半永久的なオブジェクトであるか、データベース内に存在し更新が必要なオブジェクトであるかによります。質問からは明らかではないので、十分公平です。+1
pdr

3
私の経験から、これらの種類の割引ビジネスルールは、気まぐれなマーケティング/販売部門によって常に変更されます。完全にコード駆動型ではなく、データ駆動型でユーザーが変更可能にする必要があります。これはモデルの選択にどのように影響しますか?
-jfrankcarr

@jfrankcarr私の考えでは、そうではありません。ある種の構成から、値引き、割引率などにつながるアイテムのセットの値を設定します。ステートマシンの遷移と、デコレータと戦略の属性を動的に構築する並べ替え。
トーマスオーエンズ

10

まあ、私は「Precondition」と「Discount」のペアとして割引モデルを設計します。「Precondition」はメソッドを持つクラスです

  bool IsFulfilled(Customer c);

または

  bool IsFulfilled(Customer c, Order o);

と割引には方法がありvoid ApplyTo(Customer c)ます。これにより、あらゆるタイプの前提条件とあらゆるタイプの割引を組み合わせることができます(これは「ブリッジパターン」の一種だと思います)。

前提条件の数が決まっている場合、特定のサブタイプ(戦略パターン)を作成することで問題を解決できます。ただし、AND、OR、NOTなどの論理ステートメントを使用して前提条件を非常に複雑にすることが許可されている場合は、条件に対して何らかの種類のルールインタープリターを実装することをお勧めします。ルールは、単純な「ドメイン固有言語」で記述されたプレーンテキスト文字列にすることができます。

「Discount」クラスについても同じことが言えます。さまざまなタイプの割引にいくつかのサブタイプを設定するか、割引ルールをテキスト形式で指定し、インタープリターが評価する一般的なアプローチを使用できます。


私の直感では、これは彼が質問の文脈で探しているものかもしれない示唆
超人

4
  • おそらく、すべての異なる割引は同じものであるため、IDiscountインターフェイスが必要になります。これらを一般的な割引として概念的に扱いたいと思います。

  • 「この顧客の注文」クラスには、おそらく割引のコレクションが必要です。リスト?ハッシュ?リンクリスト?まだ気にしません。割引は顧客ではなく購入に適用されます!

  • 顧客、ショッピングカート、履歴などとは別の割引インスタンスを作成してください。@ jfrankcarrが指摘したように、大幅に変更されます。

  • おそらく、各割引のアルゴリズムとパラメーターは大きく変化し、予測できないため、各割引には異なるクラスがあります。

  • 割引計算はショッピングカートの変更に対応し、その逆も同様であるため、多くのイベント処理が見られます。

デザインパターンアプリケーション

  • が表示されますstrategy pattern。IDiscountは、さまざまな割引アルゴリズムを実装するためのインターフェイスです。
  • が表示されますfactory。確かに本格的なものではなくabstract factory pattern、分析のこの時点での単一のクラスです。合理的には、どの割引が適用されるかを決定し、それを作成するのに十分なコンテキストがある単一の場所がなければなりません。1つのクラス。マーケティング部門のマッシュルームパーティーのために割引を適用するためのルールが後で爆発する場合、追加の割引構築ロジックは、この基本ファクトリクラスでまだ結合する必要があると思います。

  • 見えChain of Responsibilityます。これは、factoryアイデアと相互に排他的ではありません。割引コレクションを繰り返す代わりに、各割引は次の人を呼び出します。この場合、「顧客の注文」クラスは割引のコレクションを保持しません。

  • Chain of Responsibilityの「うーん...」要素は、各割引には次への参照があるということだと思います。意味は、順序が重要であることです。そうではありません。また、CoRが具体化する概念は、1つのオブジェクトが要求を処理できないため、「次の上位の権限まで」渡されるということです。私たちのモデルは異なります。唯一の要求は計算することです。すべての割引はこれを行います。出力または効果はnullでもかまいませんが、すべての割引が計算されます。私は本能的に、より高い実世界の忠実度に傾いています。

仮定

  • 割引は、現在のショッピングカートや購入履歴に基づいています
  • ゼロ以上の割引が適用される場合があります。相互に排他的な割引はありません
  • 適切な計算は、割引が適用される順序に依存しません。

何が変わり、何が変わらないのか?

  • 割引は非常に異なります。各ルールを構成するパラメーターの数と種類が異なります。

  • 適格な割引の引数は、ショッピングカートが変わると変わります。

  • 利用可能な割引の数の変更

  • この顧客の割引は、ショッピングカートの変更に伴う変更の対象となります。

  • この購入のコンテキストではショッピング履歴は変更されません

  • 総費用は、購入ラインと適用される割引の関数として動的に変化します。

  • 最初の適用後、割引の出力は、たとえば購入数量が変わると変化する場合があります。


素晴らしく完全な答え...しかし、私は心配しているだけで、少なくとも答えを導くために、仮定セクションがそこにあるべきではないということです。全体的な考えは、パターンは正確に快適さを与え、「仮定」を忘れるのに役立ち、一般的なルールは計算がどのように行われ、詳細な実装がコンテキストから何を使用するかを知る必要がないということです(顧客、カートアイテム、日中、季節など)。しかし、完全に役立つ
-le0diaz

最初の箇条書きと「前提条件」セクションは、割引モデルの設計に影響を与える問題自体についての「作業を表示する」だけの理由です。たとえば、割引の実行順序と相互依存についての私の仮定は、責任の連鎖を強調しないことにつながります。@docbrownのような複雑さではなく、パターンの意図について考えていることに注意してください。私はデザインの意図を反映するための熱烈な支持者です。
レーダーボブ

1

論理的には、割引モデルは何でもかまいませんので、すべてのケースを事前にプログラムできるとは限りません。あなたの質問に答える誰もがあなたが実際に必要とするものを完全に確信することもできません。ただし、現実の世界で見られる通常の種類の割引を受けると仮定すると...

大きな質問は、割引をプログラムするかどうか、またはユーザーに割引を入力してもらうかどうかです。前述のように、それらをプログラムすることはできませが、通常は、すべてをプログラミングするのではなく、一般的な場合のようにデータ入力を増やすことを目標とします。プログラマーがすべての割引を作成するために使用されている場合でも、これはある程度適用されます。

マーティン・ファウラーは、会計システムに「転記ルール」を実装する方法の一部として、「分析パターン:再利用可能なオブジェクトモデル」の「個別インスタンスメソッド」に言及していますが、ルールはかなり似ています。詳細をお伝えしますが、著作物です。

ユーザーインターフェイスの場合は、かなり単純なユースケースを考え出すか、インタープリターとクエリビルダーを構築する必要があります。1つは単純なケース用で、もう1つはより高度なものです。インタープリターを作成する場合、パーサージェネレーターと比較してコーディングが比較的簡単であり、解析時間が遅いことはおそらく重要ではないため、これはインタープリターパターンを使用するためのかなり良いケースです。(パーサージェネレーターを使用したい場合は、私を止めさせません)。

ただし、インタープリターですべてをやろうとしないでください-ある時点で、あなたは自分の不器用な言語でプログラミングしているだけなので、実際の言語を使用することもできます。インタプリタ言語が関数をサポートしている場合(おそらくそれらの呼び出しをサポートする必要があります-それらの定義は疑わしいです)、それらは実際の言語でコーディングできます。必要以上にこの道を進んで行かないでください。

何をするにしても、最終的に誰かがプロモーションの30営業日以内に購入したかどうかに基づいて割引を希望します。営業日は、店舗の郵便番号またはクライアントのいずれかによって定義される地域に休日がない郵便番号。したがって、事前に完全なシステムを設計しようとしないでください。新しい種類の割引のためにコードを記述する必要がある場合があると想定し、それに応じて設計してください。


0

これに役立つパターンがあるかどうかを尋ねるポイントはありますか?どのタイプのパターンが必要ですか-構造的または行動的ですか?

理想的には、このためのソフトウェアを作成する場合、必要なのはアルゴリズムのみです。次のように合計割引を計算する単純な関数:

cart.calculateDiscount(productVector);

これ以上必要なものはありません!

明確にするために、私は多くのルールがあることを理解しています-そのような表現の最も基本的なものはルールベース(データ属性のセットとその結果の割引)であり、上記のような関数はそれを反復して計算する必要があります。ルールが追加または削除された場合、コードを変更しないでください。ルールベースを変更するだけです。

パターンは、異なるオブジェクトが互いのAPIにアクセスしたり、タスクを配置するために通信する必要がある場合にのみ必要になります。

PS:考えてみてください-ファイアウォールがパケットを処理し、パケットを通過または拒否する(または変更する)とき-使用する設計パターンは何ですか?答えは上記のどれでもありません!


もちろん、それ以上のものが必要です!!!。アルゴリズムは、コードの実装と密接に結びついていないという考え方です。より多くのシナリオが登場する可能性が高いことをシナリオで確認すると、また何らかの形で言及しましたが、他の「ルール」が依存するものは実際にはありません。ルールは製品リストにのみ依存すると考えるのは単純ですが、実際には顧客、時間、季節などに依存します。どのファイアウォールの実装をチェックしたかわかりませんが、私がチェックしたものには多くの構造/設計パターンがあります
-le0diaz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.