2015-12-21 44 views
3

我有一個叫Coupon的模型,它可以設置爲money_offpercent_off屬性(它一次只能有一組)。我應該繼承這個Rails模型嗎?

還取決於Couponmoney_off還是percent_off更改使用哪種方法。

Im和想知道如果我應該使用單表繼承eseentially子類Coupon,有一個子類,它使用折優惠券涉及另一個處理又折優惠券

我想知道用戶如何從視圖中選擇它。

+0

嗯,這一切都取決於。繼承是一種方式。 [注射]策略 - 另一種。分支('如果coupon_type ==:money_off')到處都是 - 另一個。很難說沒有更多關於你的應用程序和它的需求的更好的信息。 –

+0

謝謝你,我願意嘗試,避免分支,如果我可以保持我的代碼清潔。我從來沒有聽說過注射策略。 –

+0

任何鏈接到我可以找到更多信息「注射策略」? –

回答

3

最好的方法是確定每個班級需要哪些功能。如果你只需要改變少量,然後堅持一個類有enum

#app/models/coupon.rb 
class Coupon < ActiveRecord::Base 
    enum type: [:percent, :money] 

    def value 
     if type.percent? 
     # ... 
     elsif type.money? 
     # ... 
     end 
    end 
end 

這將允許你使用你的實例方法type,不應該因爲如果這樣的問題你在課堂上沒有很多變化。

這將允許您撥打:

@coupon = Coupon.find x 
@coupon.value #-> returns value based on the type 

-

替代(STI)會更結構化的變化,如果你明確地引用每一個類只會工作:

#app/models/coupon.rb 
class Coupon < ActiveRecord::Base 
end 

#app/models/percent.rb 
class Percent < Coupon 
    def amount 
     # ... 
    end 
end 

#app/models/money.rb 
class Money < Coupon 
    def takeout 
     # ... 
    end 
end 

這裏的一個重要因素是你如何稱呼這些。

對於上述類,你必須引用自己的subclassed類:

@percentage_coupon = Percent.find x 
@money_coupon  = Money.find y 

這顯然會更麻煩,甚至可能會造成問題與你的路由&控制器等

....因此它可以與單一類中最好去:)

+0

哇,這是偉大的正是我一直在尋找 –

+0

還邊注是確定的名字你的enum'type',我認爲是保留的? –

+0

@SamMason:我不會冒險:) –

3

您可以做的是在內部維護策略,並提供諸如price,discounted?,discounted_price等方法。另外,無論管理員是否選擇輸入百分比或固定單位,您仍然可以提供兩種方法:discount_pct,discount_units,這將內部實現如何計算其返回值。

通過這種方式,原始類仍支持該概念(與數據模型相同),但也足夠靈活以允許各種方式爲其提供必要的輸入。無論您希望向客戶展示客戶的價格還是固定價格單位,都可以獨立於管理員的首選輸入方法。

即使是內部方法也可以使用這些抽象。如果事實證明,如果你在內部的所有地方都可以,那麼你可以爲策略創建嵌套類,並在從數據庫獲取記錄時實例化正確的類。

+0

如果我想查看一張優惠券是否是百分之百的錢,我怎麼用一種方法來檢查。 如果.coupon_type是:金錢關 self.calc_money_off 其他 self.calc_percent_off 結束 將類似的東西的工作? –

+0

如果您有優惠券的單獨表格,則優惠券的模型可以有一個類型。至於項目,你可以有一個'.coupon'方法返回它的相關優惠券(或'nil',或者一些默認的退化優惠券),並且該項目的定價方法可以依賴於它有或沒有的優惠券的類型。那麼你仍然可以使用'item.price','item.discounted_price',如果你想知道類型,'item.coupon.type if item.discounted?'。 –

+0

啊有沒有項目模型,我會用優惠券直接進行檢查,並且不會有任何相關的模型,它不是一個典型的購物系統 –

4

下面是說明了策略的使用(約其陰發佈更詳細的解答)的例子:

class Coupon < Struct.new(:original_price, :amount_off, :type) 
    def price_after_discount 
    discount_strategy.call(self) 
    end 

    private 

    def discount_strategy 
    # note: no hardcoding here 
    klass = type.to_s.camelize # :money_off to 'MoneyOff' 
    "Coupon::#{klass}".constantize.new  
    end 

    class MoneyOff 
    def call(coupon) 
     coupon.original_price - coupon.amount_off 
    end 
    end 

    class PercentOff 
    def call(coupon) 
     coupon.original_price * (1.0 - coupon.amount_off/100.0) 
    end 
    end 
end 

Coupon.new(150, 10, :money_off).price_after_discount # => 140 
Coupon.new(150, 10, :percent_off).price_after_discount # => 135.0 

現在,而不是創建一個策略在內部,我們可以在構造函數中接受它,從而使策略成爲「可注射」的。