禮貌性實作
2004 年 8 月 12 日
當你撰寫類別時,你通常會努力確保該類別的功能對該類別有意義。但有時,新增一個功能讓類別符合它自然應該具備的更豐富介面是有意義的。
最常見且顯而易見的範例就是使用複合模式時會遇到的範例。讓我們來考慮一個簡單的容器範例。你有一些盒子,可以裝其他盒子和大象(這是虛擬大象的優點)。你想知道一個盒子裡有多少大象,考慮到你需要計算盒子裡、盒子裡的盒子裡、盒子裡的盒子裡的大象。當然,解決方案就是一個簡單的遞迴。
# Ruby class Node end class Box < Node def initialize @children = [] end def << aNode @children << aNode end def num_elephants result = 0 @children.each do |c| if c.kind_of? Elephant result += 1 else result += c.num_elephants end end return result end end class Elephant < Node end
現在,kind_of?
測試在 num_elephants
中是一個警訊,因為我們應該小心任何測試物件類型的條件。另一方面,還有其他選擇嗎?畢竟我們會進行測試,因為大象無法包含盒子或大象,所以詢問牠們裡面有多少大象沒有意義。詢問大象牠們包含多少大象不符合我們的世界模型,因為牠們無法包含任何東西。我們可能會說這沒有模擬真實世界,但我的範例對這個論點來說感覺有點太異想天開了。
然而,當人們使用複合模式時,他們通常會提供一個方法來避免條件 - 換句話說,他們會這樣做。
class Node #if this is a strongly typed language I define an abstract #num_elephants here end class Box < Node def initialize @children = [] end def << aNode @children << aNode end def num_elephants result = 0 @children.each do |c| result += c.num_elephants end return result end end class Elephant < Node def num_elephants return 1 end end
許多人對這種事情感到非常不安,但它確實可以極大地簡化掃描複合結構的程式碼邏輯。我把它想成讓葉類別(大象)提供一個簡單的實作,作為它在階層中作為節點的角色的禮貌。
我喜歡畫的類比是數學中將數字提升到 0 次方的定義。定義是任何數字提升到 0 次方都是 1。但直覺上,我不認為說任何數字乘以它自己 0 次是 1 有道理 - 為什麼不是零?但這個定義讓所有數學運算順利進行 - 所以我們暫停我們的懷疑並遵循定義。
每當我們建立模型時,我們都在設計一個模型來適應我們想要感知世界的方式。如果禮貌性實作簡化了我們的模型,那麼它們就是有價值的。
於 2014 年 8 月 27 日重新發布