2008-10-16 53 views
5

希望我沒有誤解「duck typing」的含義,但是從我讀過的內容來看,這意味着我應該根據對象如何響應方法而不是它是什麼類型/類來編寫代碼。我可以用鴨子打字改進這種方法嗎?

下面的代碼:

def convert_hash(hash) 
    if hash.keys.all? { |k| k.is_a?(Integer) } 
    return hash 
    elsif hash.keys.all? { |k| k.is_a?(Property) } 
    new_hash = {} 
    hash.each_pair {|k,v| new_hash[k.id] = v} 
    return new_hash 
    else 
    raise "Custom attribute keys should be ID's or Property objects" 
    end 
end 

我要的是確保我最終有一個哈希密鑰是代表一個ActiveRecord對象的ID的整數。我並不特別喜歡用all?兩次遍歷散列鍵來確定是否需要獲取ID。

當然,我會接受任何其他建議,以改善這個代碼,以及:)

+0

甚至從來沒有聽說過「鴨打字」的。你在哪裏遇到過這個問題? – 2008-10-16 17:27:00

+0

@布萊恩,http://en.wikipedia.org/wiki/Duck_typing – 2008-10-16 17:29:41

回答

11

你怎麼寫這種方法應該取決於您是否希望正常程序執行過程中被拋出異常。如果你想要一個可讀的異常消息,因爲最終用戶可能會看到它,那麼手動拋出一個是有道理的。否則,我只是做這樣的事情:

def convert(hash) 
    new_hash = {} 
    hash.each_pair { |k,v| new_hash[ k.is_a?(Integer) ? k : k.id ] = v } 
    return new_hash 
end 

這將完成同樣的事情,你仍然會得到一個異常,如果數組鍵沒有一個ID字段。更好的是,這會使用更多的鴨子打字,因爲現在任何具有id字段的東西都是可以接受的,這比明確地檢查某個屬性是好的。這使得你的代碼更加靈活,特別是在單元測試時。

我們仍然對整數對象有明確的檢查,但這種偶然的特殊情況通常是可以接受的,尤其是在檢查內置數據類型時。

3

鴨子打字實際上只是多態的細微版本。在Java這樣的靜態類型語言中,你必須創建一個明確的接口,告訴編譯器一個特定變量可以接受的所有方法。使用像Ruby這樣的動態語言,接口仍然存在抽象意義,它們只是隱含的。

問題是,您將兩種不同的數據結構接受爲一種方法。使鴨子打字工作的方法是要求傳遞給你的方法的所有對象服從同一個契約(即它總是一個整數到[Foo]對象的散列)。將一個帶有屬性鍵的散列轉換爲正確的結構應該是客戶代碼的工作。這可以通過一個簡單的包裝類或由您的elseif子句構成的轉換函數輕鬆完成。

底線是由調用該方法的人來確定他的參數都會讓你的方法期望他們嘎嘎的方式嘎嘎。如果他們不這樣做,他就是那個需要弄清楚如何像鴨子一樣製造火雞嘎嘎聲的人,而不是你。

0

我想要的是確保我最終得到一個散列,其中的鍵是一個表示ActiveRecord對象ID的整數。

您應該在創建/插入散列時檢查。你可以嘗試這樣的事:

 
h = {} 
def h.put obj 
    self[obj.id]=obj 
end 

也許

 
h = {} 
def h.[]= key, value 
    raise "hell" unless key == value.id 
    super 
end 
相關問題