在Ruby中,如何将属性标记为脏的?
假设我有以下课程:在Ruby中,如何将属性标记为脏的?,ruby,Ruby,假设我有以下课程: class Cashier def purchase(amount) (@purchases ||= []) << amount end def total_cash (@purchases || []).inject(0) {|sum,amount| sum + amount} end end 班级出纳 def采购(金额) (@purchases | |=[])最简单的方法是维护另一个变量,以指示@purchases是否
class Cashier
def purchase(amount)
(@purchases ||= []) << amount
end
def total_cash
(@purchases || []).inject(0) {|sum,amount| sum + amount}
end
end
班级出纳
def采购(金额)
(@purchases | |=[])最简单的方法是维护另一个变量,以指示@purchases
是否脏。例如:
class Cashier
def initialize(*args)
# init @purchases and @total_cash
@is_purchases_dirty = false
end
def purchase(amount)
(@purchases ||= []) << amount
@is_purchases_dirty = true
end
def total_cash
return @total_cash unless @is_purchases_dirty
@is_purchases_dirty = false
@total_cash = (@purchases || []).inject(0) {|sum,amount| sum + amount}
return @total_cash
end
end
我还建议你不要使用昂贵的手术命名方案。我会将total\u cash
重命名为类似calc\u total\u cash
的名称,以便告诉API用户,这是一个相对昂贵的调用,而不是简单的getter/setter。在最简单的情况下,您可以为要标记为dirty的对象定义一个实例变量。修改变量时(在购买方法中)将其设置为true
检查现金总额中的值
;如果是,请使用total的缓存版本。否则,计算新值并将其存储在缓存中
class Cashier
def purchase(amount)
@purchases_dirty = true
(@purchases ||= []) << amount
end
def total_cash
@total_cash = (@purchases || []).inject(0) do |sum,amount|
sum + amount
end if (@purchases_dirty || @total_cash.nil?)
@purchases_dirty = false
@total_cash
end
end
班级出纳
def采购(金额)
@购买脏的=真的
(@purchases | |=[])如果您愿意,您可以比其他答案更进一步。您可以编写更改代码的代码,而不是将代码更改为仅在必要时重新计算。每个人都喜欢元编程
下面是一些代码,它使用执行可能很长计算的方法的名称,以及调用时使以前的任何计算无效的方法的名称列表,并编写代码来包装这些方法,仅在必要时执行计算,如果没有,则返回存储值
module ExpensiveCalculation
def recalc_only_if_necessary(meth, *mutators)
aliased_method_name = "__#{meth.object_id}__"
value = "@__#{meth.object_id}_value__"
dirty_flag = "@__#{meth.object_id}_dirty__"
module_eval <<-EOE
alias_method :#{aliased_method_name}, :#{meth}
private :#{aliased_method_name}
def #{meth}(*args, &blk)
#{dirty_flag} = true unless defined? #{dirty_flag}
return #{value} unless #{dirty_flag}
#{value} = #{aliased_method_name}(*args, &blk)
#{dirty_flag} = false
#{value}
end
EOE
mutators.each do |mutator|
aliased_mutator = "__#{meth.object_id}_#{mutator.object_id}__"
module_eval <<-EOE
alias_method :#{aliased_mutator}, :#{mutator}
private :#{aliased_mutator}
def #{mutator}(*args, &blk)
#{dirty_flag} = true
#{aliased_mutator}(*args, &blk)
end
EOE
end
end
# this hook is used to make the new method
# private to the extended class.
def self.extend_object(obj)
super
obj.private_class_method :recalc_only_if_necessary
end
end
模块费用计算
def recalc仅在必要时使用(meth,*突变剂)
别名_method_name=“uu#{meth.object_id}uu”
value=“@_35;{meth.object_id}u value_35;”
dirty_flag=“@_35;{meth.object_id}u dirty_35;”
模块评估对Naming提出了很好的建议,可能没有必要每次都从头开始重新计算总数。只要用@total\u cash+=amount
@hammer:呃,是的。。。我甚至没有真正了解代码在做什么=D。这一点很好。无关的注释:如果您想更简洁,可以执行inject(0,:+)
。
module ExpensiveCalculation
def recalc_only_if_necessary(meth, *mutators)
aliased_method_name = "__#{meth.object_id}__"
value = "@__#{meth.object_id}_value__"
dirty_flag = "@__#{meth.object_id}_dirty__"
module_eval <<-EOE
alias_method :#{aliased_method_name}, :#{meth}
private :#{aliased_method_name}
def #{meth}(*args, &blk)
#{dirty_flag} = true unless defined? #{dirty_flag}
return #{value} unless #{dirty_flag}
#{value} = #{aliased_method_name}(*args, &blk)
#{dirty_flag} = false
#{value}
end
EOE
mutators.each do |mutator|
aliased_mutator = "__#{meth.object_id}_#{mutator.object_id}__"
module_eval <<-EOE
alias_method :#{aliased_mutator}, :#{mutator}
private :#{aliased_mutator}
def #{mutator}(*args, &blk)
#{dirty_flag} = true
#{aliased_mutator}(*args, &blk)
end
EOE
end
end
# this hook is used to make the new method
# private to the extended class.
def self.extend_object(obj)
super
obj.private_class_method :recalc_only_if_necessary
end
end
class Cashier
extend ExpensiveCalculation
def purchase(amount)
(@purchases ||= []) << amount
end
def total_cash
(@purchases || []).inject(0) {|sum,amount| sum + amount}
end
recalc_only_if_necessary :total_cash, :purchase
end