2009-06-16 54 views
0

我正在開發在線商店,客戶需要能夠刪除訂單並使其產品自動補貨(例如,針對測試訂單)。這是我第一次嘗試實現這個:混淆方法是不是皺起了眉頭?

class Order < ActiveRecord::Base 
    def destroy_and_restock 
    restock_products 
    destroy 
    end 

    protected 

    def restock_products 
    line_items.each do |li|  
     li.product.quantity_on_hand += li.quantity 
     li.product.save 
    end 
    end 
end 

但是,如果我以後需要創建另一個destroy_and_x方法是什麼?爲什麼不允許將X作爲參數傳遞給destroy()方法?所以現在我正在考慮這樣做:

alias :old_destroy :destroy 
def destroy(options = {}) 
    if options['restock'] == true 
    restock_products 
    end 
    old_destroy 
end 

protected 

def restock_products 
    line_items.each do |li|  
    li.product.quantity_on_hand += li.quantity 
    li.product.save 
    end 

這是更具擴展性,但讓我覺得有點髒。我感覺髒了我錯了嗎?有沒有更好的方法來做到這一點?

+1

什麼是X?那是沒有道理的。會有多少X? 不要因爲擴展性以外的其他原因而使事物「可擴展」。 – whatsisname 2009-06-16 03:58:58

+0

在需要時擔心可擴展性。除非有真實案例,否則很難知道要延伸什麼。 – 2009-06-16 04:04:18

+0

X可以等於「退款」,我想(如@ order.destroy_and_refund)。 – 2009-06-16 04:13:49

回答

2

我會說「是的,這是髒的。」您的意圖不是修改「銷燬」方法的行爲,而是執行一些特定於域的工作,然後運行destroy。你的第一種方法很好 - 定義一個你想要的方法,並根據需要調用destroy。正如你正在考慮的那樣,我認爲'包裝'或'猴子補丁'是一種最適用於標準面向對象方法的技術 - 例如,當你需要修改/增加行爲在您的控制範圍之外定義和使用的類。

即使你考慮修改destroy方法本身的行爲,我建議這裏覆蓋的方法,而不是它包裝:

def destroy(options = {}) 
    restock_products if options['restock'] 
    super() # I think parens are necessary here, to avoid passing options up the chain 
end 
0

如何只使用塊?然後,你沒有拉開你的頭髮,而在課堂上設計這一點,你可以做更多,當你需要:

def destroy_after &block 
    yield if block 
    destroy 
end 

然後調用它像這樣:

order.destroy_after { order.restock_products } 

我不能想想這個功能的好名字......但我希望你明白這個主意。

0

如果猴子補丁不讓你在晚上睡覺,你可以通過繼承來實現同樣的目的。當我需要快速入侵或快速調試時,我也會修補它。