我有一個叫Coupon
的模型,它可以設置爲money_off
或percent_off
屬性(它一次只能有一組)。我應該繼承這個Rails模型嗎?
還取決於Coupon
是money_off
還是percent_off
更改使用哪種方法。
Im和想知道如果我應該使用單表繼承eseentially子類Coupon
,有一個子類,它使用折優惠券涉及另一個處理又折優惠券?
我想知道用戶如何從視圖中選擇它。
我有一個叫Coupon
的模型,它可以設置爲money_off
或percent_off
屬性(它一次只能有一組)。我應該繼承這個Rails模型嗎?
還取決於Coupon
是money_off
還是percent_off
更改使用哪種方法。
Im和想知道如果我應該使用單表繼承eseentially子類Coupon
,有一個子類,它使用折優惠券涉及另一個處理又折優惠券?
我想知道用戶如何從視圖中選擇它。
最好的方法是確定每個班級需要哪些功能。如果你只需要改變少量,然後堅持一個類有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
這顯然會更麻煩,甚至可能會造成問題與你的路由&控制器等
....因此它可以與單一類中最好去:)
哇,這是偉大的正是我一直在尋找 –
還邊注是確定的名字你的enum'type',我認爲是保留的? –
@SamMason:我不會冒險:) –
您可以做的是在內部維護策略,並提供諸如price
,discounted?
,discounted_price
等方法。另外,無論管理員是否選擇輸入百分比或固定單位,您仍然可以提供兩種方法:discount_pct
,discount_units
,這將內部實現如何計算其返回值。
通過這種方式,原始類仍支持該概念(與數據模型相同),但也足夠靈活以允許各種方式爲其提供必要的輸入。無論您希望向客戶展示客戶的價格還是固定價格單位,都可以獨立於管理員的首選輸入方法。
即使是內部方法也可以使用這些抽象。如果事實證明,如果你在內部的所有地方都可以,那麼你可以爲策略創建嵌套類,並在從數據庫獲取記錄時實例化正確的類。
如果我想查看一張優惠券是否是百分之百的錢,我怎麼用一種方法來檢查。 如果.coupon_type是:金錢關 self.calc_money_off 其他 self.calc_percent_off 結束 將類似的東西的工作? –
如果您有優惠券的單獨表格,則優惠券的模型可以有一個類型。至於項目,你可以有一個'.coupon'方法返回它的相關優惠券(或'nil',或者一些默認的退化優惠券),並且該項目的定價方法可以依賴於它有或沒有的優惠券的類型。那麼你仍然可以使用'item.price','item.discounted_price',如果你想知道類型,'item.coupon.type if item.discounted?'。 –
啊有沒有項目模型,我會用優惠券直接進行檢查,並且不會有任何相關的模型,它不是一個典型的購物系統 –
下面是說明了策略的使用(約其陰發佈更詳細的解答)的例子:
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
現在,而不是創建一個策略在內部,我們可以在構造函數中接受它,從而使策略成爲「可注射」的。
嗯,這一切都取決於。繼承是一種方式。 [注射]策略 - 另一種。分支('如果coupon_type ==:money_off')到處都是 - 另一個。很難說沒有更多關於你的應用程序和它的需求的更好的信息。 –
謝謝你,我願意嘗試,避免分支,如果我可以保持我的代碼清潔。我從來沒有聽說過注射策略。 –
任何鏈接到我可以找到更多信息「注射策略」? –