2013-02-20 102 views
1

我被賦予了一項任務,那就是編寫一個簡單的程序來打印一份雜貨店顧客的收據。知道基本銷售稅適用於所有商品的10%稅率,但免除的書籍,食品和醫療產品除外。 進口關稅是對所有進口貨物適用的附加銷售稅,稅率爲5%,無豁免。面向對象的設計

示例輸入:1美元10美元的書籍,1美元的進口巧克力條,5美元等等。

我想使程序儘可能以對象爲導向。所以我的層次是這樣的:

頂層是抽象類Item(name,price),然後我將有類SaleTaxItem(需要支付10%稅的項目)和NonSaleTax項目類從Item擴展。問題是我應該在上面的每個類中創建一個名爲isImported的布爾變量,以便我知道何時收取5%的費用?或者我應該爲導入的項目創建一個新類?

這個設計對於這個任務非常重要,所以我想讓它完美。謝謝!

+1

爲什麼不只是寫一個方法'getTax ()'哪些返​​回10%的SaleTaxItem和10%+ 5%的項目是否可以進口(可能重寫?)?我不認爲布爾是一個很好的可擴展選擇:想象一下,我們引入了新的稅收:我們是否需要引入新的布爾值?我們是否需要在int中進行編碼? – 2013-02-20 06:45:44

+0

雅我有getTax()其中我目前使用布爾值來決定是否收取5%的進口稅。我在Item類中實現了is_import布爾值。如果我不使用布爾值,那麼我應該使用什麼? – 2013-02-20 07:03:44

回答

2

關於何時使用繼承以及何時不使用,存在着巨大的討論。在這種情況下,我會而不是使用繼承來建模您的項目。

爲什麼?因爲在現實生活中,這些稅收和責任規則在時間,空間(例如你所在的國家)以及你正在運行的公司類型中經常發生變化。如果每當地方政府和聯邦政府更改其規定時都必須更改班級層級,那麼您註定會失敗 - 更新會更改您已擁有實例的班級 - 您的項目。另一個考慮:如果您使用類(有效地)將銷售標記爲具有稅收和/或責任,那麼您將最終得到一些沒有標記接口的項目,並且一些項目具有多個 - 即使用多重繼承。你需要四個班級。添加一些額外的規則,並且你有一個班級爆炸(考慮稅種/職責數量的因子)。

另一種實現方式是擁有一個屬性,該屬性是項目所具有的稅收和關稅的集合。所以,你有兩個班,:

  • 項目

    • 列表:稅收
    • 字符串:命名
    • 雙:百分之

稅收有許多全局實例 - SalesTax和ImportDuty。然後,一個項目在列表中具有零個,一個或兩個Tax實例(並且該列表還暗示訂單納稅被應用)。

這最後一種方法也是更好的適應未來的稅制改革,包括增加新稅種

編輯一夜之間我有一個改進的建議:

enter image description here

有兩種'wings'to the diagram:

  1. AbstractItem層次結構,處理Item和i稅收
  2. TaxOrDuty層次結構和TaxAssessor中的算法。

AbstractItem在Item上使用decorator pattern,將Item包裝在稅層中 - 每個層由TaxedItem建模。最外層是包裹在所有適用稅款中的物品,並且使用裝飾者模式,除了虛高價格外,其外觀和行爲都與物品相同。該AbstractItem有幾個有用的方法:

  • 用getPrice():返回全價的項目
  • getAllTaxes()的:通過在一個空的列表,以及遞歸方法在裝飾收集TaxOrDuty實例。這對於能夠對裝飾物品的稅收進行分項很重要
  • getUntaxedItem():通過裝飾物遞歸直到它找到它返回的物品。這可以輕鬆從裝飾物品中檢索原始物品。

在稅收方面,有一類TaxOrDuty模擬稅收的抽象行爲。在這個天真的實現中,每個稅都有一個統一的稅率,但是您可以輕鬆地將該行爲推到FlatRateTax類中。其方法是:

  • 的getRate():返回稅收或關稅摘要方法。這是在子類上實現的
  • computeTax()方法獲取一個項目並根據getRate()計算稅金
  • isApplicable()是一個抽象方法,如果稅項適用於Item,則返回true。這在SalesTax上執行(總是返回true)和ImportDuty(返回Item.isImported)

TaxAssessor是負責協調適用稅收分配的類。它包含所有TaxOrDuty實例的列表(在本例中只是SalesTax的一個實例和ImportDuty之一)。它的方法applyTaxes(Item)遍歷這個集合調用isApplicable()。對於返回true任何TaxOrDuty,該TaxAssessor包裹項目在TaxedItem(當然它引用TaxOrDuty)的新實例:

AbstractItem applyTaxes(Item item) { 
    taxed = item; 
    for (TaxOrDuty td : taxes) { 
      if (td.isApplicable(item)) { 
       taxed = new TaxedItem(td, taxed); 
    return taxed; 

所以你的整體答案是這樣的:

Item item = new Item("Book", 10.0, false); // New $10 book, not imported 
AbstractItem withTaxes = taxAssessor.applyTaxes(item); 
double taxedPrice = withTaxes.getPrice(); 
List<TaxOrDuty> applicableTaxes = withTaxes.getAllTaxes(new List<TaxOrDuty>()); 

這種模式的主要優點是:

  • 新稅種是可插拔
  • 納稅評估和計算算法是稅收的一部分,而不是在項目,所以非常複雜的稅收可以在自己的階級獨立且準確地模擬
  • 責任是明顯的(對我來說),並明確劃定
+0

無論如何,我可以確定哪個項目是應稅的?我的意思是,例如,我只有一個類Item,當我創建一個新的Item並向構造函數提供一個名稱「chocolate」時,構造函數會認識到巧克力是食物並且對這個價格徵稅?! – 2013-02-20 21:40:12

+1

@CharlieVictor:我已經用一個很好的模型來回答這個問題,我已經更新了我的答案。 – 2013-02-21 00:57:18