キャッシュレジスターの設計と実装:
アイテムの数を考えると、合計請求額を計算する必要があります。アイテムは、いくつかの異なる方法で課金されます。
各アイテムの特定の価格。例:チェリオスの箱はそれぞれ$ 6.99です
重量による特定の価格、例:リンゴは1ポンドあたり2.49ドルです
アイテムは、一括割引を受ける可能性のある場所で販売できます。 2つ買うと1つ無料で販売; 4つ買うと1つ無料
合計金額がしきい値を超えた場合に、請求書からお金を引き出すためのクーポンを利用できます。 100ドル以上使うと5ドルオフ
私の答え:どれだけ正しいのか、どうすれば改善できるのかわかりません!
C#に基づいてデザインを添付しました。コードは、 https://github.com/mandanemedia/CashRegister で表示できます。
継承がより良いか、構成を理解するのを手伝っていただければ幸いです。与えられたシナリオに基づいて、答えには次の具体的なクラスが必要です。
2つのオブジェクトShoppingCartとShoppingCartByCouponと同様に、またはShoppingCartオブジェクトのみである可能性があります。
私の目標は、OOデザインスキルとデザインパターンを改善することです。
たとえば、これらのinterface
sは必要ないと断言します。後で必要な場合は、後で作成します。
interface
(C#キーワードの種類)は、無関係のクラスに共通の動作を与えてから、オブジェクトを多態的に処理するためのものです。
より具体的なクラスを構成するものについて、より慎重に考えてください。ショッピングカートとは何かを考えてみてください。 「クーポンショッピングカート」はより具体的な種類のカートですか、それとも単にカートの属性ですか。
すべてを別個の別個のビットとして見るのとは対照的に、物事がどのように連携するかについてより慎重に考えてください。クーポンは、価格計算の論理的な部分です。 GetPrice
は、単に製品クラスで必要な「grunt」メソッドです。
「グループセール」はボリュームディスカウントです。これはクーポンと同じ概念です。どちらも割引です。別の言い方をすれば、それらは単に価格の調整です。したがって、それらはコスト計算の不可欠な部分です。それらはクラスではありません。
interface
が多すぎます実装ではなくインターフェイスへのコードすべてを(C#キーワード)interface
にすることを意味するわけではありません。任意のクラスのパブリックメソッドのセットISインターフェイス。
抽象クラスから継承する代わりにインターフェースを実装すると、多くの冗長な実装が可能になります。
これは、_Interface segregation
_原則のグロテスクな(申し訳ありませんが)誤用です。 ISell
がそれ自体を別個のinterface
として正当化する方法がわかりません。 ISell
参照が渡されているのがわかりません。 GetPrice()
は、自然にProductXXX
オブジェクトに属しているように見えます。その意味は、機能クラス内でより明確になります。
ショッピングカートも同様です。
抽象化すると、複数の_ProductSellBy...
_クラスが1つに合体することを強く疑っています。
これらは単なる値です。そして、これらの値は同じ方法で計算に使用されます。つまり、GetPrice() * Quantity()
quantity
が可算名詞または重みを表すという事実は、別のプロパティで取得できます。これにはすでにenum
があります。そのタイプのプロパティを、Product
クラスに作成してください。
この抽象化により、多くのインターフェイスやクラスの動機がなくなり、ダイアグラムが半分以上縮小すると思います。
abstract
sのProduct
クラスを作成します。
ShoppingCart coupon
_「クーポンによる」は、ショッピングカートのサブクラスとしては意味がありません。クーポンは単に価格計算の調整です。
上記のように、interface
をサブクラス化する必要がある場合は、それらのabstract
sを削除し、ShoppingCart
クラスを作成します。
そして、あなたがそれについて考えるとき、クーポンは本当に特別な場合ではありません。コストはどのアイテムでも同じようにクーポン割引されると思います。そのため、価格計算に割引を組み込むことができます。これは、割引を表さないクーポンのデフォルト値に対応しています。