我有一个叫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')到处都是 - 另一个。很难说没有更多关于你的应用程序和它的需求的更好的信息。 –
谢谢你,我愿意尝试,避免分支,如果我可以保持我的代码清洁。我从来没有听说过注射策略。 –
任何链接到我可以找到更多信息“注射策略”? –