2012-06-27 18 views
2

我認爲我可能不會用最紅寶石的方式編寫懶惰的實例化方法/屬性。以此方法爲例:寫一個多行懶惰計算方法的ruby方法是什麼?

def tax 
    @tax ||= Proc.new do 
    if flat_tax > commission_plan.tax_max 
     return commission_plan.tax_max 
    end if commission_plan.tax_max 
    if flat_tax < commission_plan.tax_min 
     return commission_plan.tax_min 
    end if commission_plan.tax_min 
    flat_tax 
    end.call 
end 

是否有更像ruby的方式來重構此方法?

+0

...爲什麼你在那裏創建一個匿名函數? – YuriAlbuquerque

+3

我有點驚訝,如果faz結束,如果baz是有效的Ruby。但是,請不要寫這樣的代碼! –

回答

6
def tax 
    @tax ||= calc_tax 
end 

private 

def calc_tax 
    min, max = commission_plan.tax_min, commission_plan.tax_max 
    if (min..max).include? flat_tax 
    flat_tax 
    else 
    flat_tax > max ? max : min 
    end 
end 
+0

我幾乎寫了一個避免鏈接條件的解決方案......但是您的解決方案無法處理他原來的無法檢查。儘管將calc_tax設置爲私有的很好。 –

+0

@RyanSandridge好眼睛......猜我的大腦沒有解析這一點。 +1給你 –

+0

很好的答案。如果爲零,我只是更改了賦值語句以將min和max設置爲flat_tax。完美的作品,更像紅寶石般的。 – barelyknown

1

我不明白你爲什麼要創建這個匿名函數。這是......多餘的。這是一個更好的和更清潔的代碼:

def tax 
    return commission_plan.tax_max if commission_plan.tax_max && 
     flat_tax > commission_plan.tax_max 
    return commission_plan.tax_min if commission_plan.tax_min && 
     flat_tax > commission_plan.tax_min 
    return flat_tax 
end 

有實現它的其他方式,但是這是一個很大的改善相比,你那裏。

+0

讓我們假設計算比這個例子更昂貴,並且我想在一次計算一次實例變量@tax時將結果存儲在實例變量@tax中。在那種情況下,我應該設置|| =來。 – barelyknown

2

你在問什麼叫Memoization。正如Yuri所建議的那樣,您爲此使用Proc是非常尷尬的。

這是我的快速重構。我可能還會進一步重構這個......但它是一個簡單的重構,它更多的是Ruby-ish。

def tax 
    @tax ||= calculate_tax 
end 

def calculate_tax 
    if commission_plan.tax_max && flat_tax > commission_plan.tax_max 
    commission_plan.tax_max 
    elsif commission_plan.tax_min && flat_tax < commission_plan.tax_min 
    commission_plan.tax_min 
    else 
    flat_tax 
    end 
end 

此外,如果您不介意包括一些外部依賴項,請檢查ActiveSupport::Memoizable。這裏有一篇關於memoization的文章。

2

如果您不想向外部庫添加依賴項,您可以輕鬆地添加自己的「memoize」助手。沿着線的東西:

class Class 
    def memoize(method) 
    original_method = instance_method(method) 
    instance_var = "@__#{method}__".to_sym 
    define_method(method) do |*a,&b| 
     cached = instance_variable_get(instance_var) 
     unless cached 
     cached = old_method.bind(self).call(*a,&b) 
     instance_variable_set(instance_var, cached) 
     end 
     cached 
    end 
    end 
end 

然後用法是這樣的:

def tax 
    # expensive calculation here 
end 
memoize :tax 

如果你不喜歡這種memoize接口,你可以把它改成任何你喜歡的。這是紅寶石,寶貝!你可以像泡泡糖一樣扭曲,彎曲和伸展的語言。也許這樣的接口將是很好:

def_memoized :tax do 
    # expensive calculation here 
end 

我喜歡把我的每個項目擴展到核心的Ruby在一個名爲​​文件。這是那種會在那裏的東西。

+0

很好的答案。我保留了其他答案,因爲它更直接,但這很有幫助。 – barelyknown

相關問題