3

現在構築中の請求システムの状態ベースの機能に頭を悩ませています。このシステムは、請求書の計算、手動承認、印刷、およびアーカイブをサポートします。

最初は、State パターンを使用してこれをモデル化する必要があると考えました。請求書は、印刷、アーカイブなどを現在割り当てられている状態に委任するコンテキストになります。

しかし、異なる状態 (作成済み、承認済み、印刷済み、アーカイブ済み) が同じ操作をサポートするべきではないため、これは明らかに悪い考えです。たとえば、以前に承認されたことのない請求書を印刷することはできません。サポートされていない操作に対して例外をスローすると、LSP に違反します。この問題の一般的な説明はこちらで見つかりまし

これを適切に実装する方法を知っている人はいますか?


PS: これはつまらない宿題のように聞こえるかもしれませんが、そうではありません。実世界のシステムにはこれが必要です。

4

3 に答える 3

1

基本的に、アプリケーションの状態のワークフローを作成しています。各状態では、請求書で使用可能な操作が変更されます。boolean canPrint()状態パターンは適切ではないように見えますが、print(). が返されたprint()場合に例外をスローできるようにするコントラクトがあります。このように、サブクラスはその契約を破ることはありません。別のオプションは、可能な場合にのみ印刷し、印刷されたかどうかを返す を使用することです。canPrint()falseboolean tryPrint()

ただし、状態がほとんど重複しない操作をサポートしている場合、状態パターンは解決策ではない可能性があります。問題に特定のパターンを当てはめようとするのではなく、一歩下がってより良い方法を探してください。1 つの方法は、「状態」ごとに必要な操作 ( 、 など) を持つ個別のクラスを作成することですCreatedInvoiceApprovedInvoiceこれらのクラスは、サポートする操作のみを持ちます。

于 2012-06-30T13:46:03.793 に答える
0

責任の連鎖パターンはここであなたを助けるかもしれません。

ハウ部分を追加し、リンクを修正します。

ハンドラークラスであるCalculator、Approver、Printer、およびArchiverクラスが存在する可能性があります。これらは、親抽象クラスからprocessRequest()をオーバーライドすることができます。請求書は、各ハンドラーのprocessRequest()メソッドに渡されるクラスにすることができます。ここでパターンを使用する利点は、新しいハンドラーを動的に追加でき、ハンドラーのシーケンスを持つチェーンリンクを簡単に変更できることです。

于 2012-06-30T13:37:31.067 に答える
0

State Pattern があなたの状況に本当に適しているかどうかは定かではありませんが、そうでない場合、Liskov が理由ではありません。ある種の「現在の状態での無効な操作」例外のスローは、状態インターフェイスで可能かつ有効であると定義でき、これを行うサブクラスは LSP に違反しません。

GoF Design Patterns bookで State パターンに使用されている古典的な例は TCPConnection であり、すべての状態でサポートされていない、または適切でない操作が確実に含まれています。たとえば、閉じた接続では送信できません。

于 2012-06-30T14:21:03.960 に答える