2011-05-26 117 views
1

我創建了一個跟蹤汽車裏程和服務歷史的程序,以便更新用戶即將到來的汽車服務需求。這看起來像Ruby的鴨子打字一樣嗎?

我有三類:Car,CarHistoryCarServiceHistoryEntry。第三個是直截了當的;它保持了與服務相關聯的所有屬性:日期,里程數,服務執行等CarHistory類如下:

require_relative 'car_service_history_entry' 

class CarHistory 
    attr_reader :entries 
    def initialize (*entry) 
    if entry.size > 1 
     @entries = [] 
    else 
     @entries = entry 
    end 
    end 
    def add_service_entry entry 
    @entries << entry 
    end 
    def to_s 
    entries_string = "" 
    @entries.each {|entry| entries_string << "#{entry.to_s}\n"} 
    entries_string 
    end 
end 
  1. initialize,應該之類的entry進行檢查?
  2. add_service_entry,採用鴨子打字(如Andy Thomas在「Programming Ruby」中的說法),我甚至會測試是否可以添加CarServiceHistoryEntry?難道我只是通過String而不是在我的單元測試中設置並添加CarServiceHistoryEntry
  3. 由於CarHistory的唯一必要屬性是entries數組和to_s方法,我應該只將這個類全部取消並放入car類中?

回答

1

對於1和2,當您移動到鬆散類型的語言(如Ruby)時,您需要釋放對「嚴格打字」的嚴格控制。

  • 你應該檢查你的輸入參數嗎?傳統的答案是肯定的。另一種方法是使用良好的名稱和單元測試來記錄和指定類型應該如何工作。如果它與其他類型一起工作,罰款..這是一個額外的好處。所以如果你傳入一個不兼容的類型,它會被一個異常炸燬,這在大多數情況下是足夠好的。嘗試一下,看看它的感受(可能的結果:解放/「撤退!」,但給它一個公平的嘗試)。 例外情況是,如果您正在爲共享庫設計公共API - 其中規則不同。你需要快速和信息錯誤地輸入。
  • 至於把car_history裝進汽車 - 我會問你的汽車類的責任是什麼。如果保持自己的歷史就是其中之一,那麼你可以將它們分開。將來,如果您發現許多方法與汽車歷史有關,您可以再次反轉此決定並再次提取CarHistory類型。使用單一責任原則做出明智的決定。這只是OOP - Ruby不會降低對象設計。

代碼段:代碼可以更簡潔

# just for simplicity, I'm making HistoryEntry a string, it could be a custom type too 
class CarServiceHistoryEntry << String 
end 

class CarHistory 
    attr_reader :entries 
    def initialize(*history_entries) 
    @entries = history_entries 
    end 

    def add_service_entry(entry) 
    @entries << entry 
    end 
    def to_s 
    @entries.join("\n") 
    end 
end 

irb>x = CarHistory.new("May 01 Overhaul", "May 30 minor repairs") 
irb>x.add_service_entry("June 12 Cracked windshield") 
irb>x.to_s 
=> "May 01 Overhaul\nMay 30 minor repairs\nJune 12 Cracked windshield" 
1

很難評論CarHistory類與其他人的關係,但我相信隨着你的發展,它會變得清晰。

兩三你的方法可以簡化,但我必須說,我不明白在initializeif,也許它只是倒退,應該已經> 0

def initialize *entry 
    @entries = entry # if not specified it will be [] anyway 
end 

def to_s 
    @entries.join "\n" 
end 

是的,Ruby應該很簡單。您不需要使用運行時類型檢查來清理代碼。如果代碼運行你的單元測試,那麼你可以聲明勝利。無論如何,顯式轉換的無數次都傾向於糾正類型錯誤。

Ruby無論如何都會在運行時檢查你的類型。將類型檢查留給解釋者並將你的努力投入功能測試是完全合理的。

0

我會跳過前兩個問題,回答第三個問題。如果CarServiceHistoryEntry的唯一屬性是一個字符串,那麼是,廢棄CarHistory(以及CarServiceHistoryEntry),並將一個service_history屬性添加到Car中,該屬性只是一個字符串數組。直到事實證明,否則,越簡單越好。

至於鴨子打字,你永遠不會想測試'是'是'只看它是否'迴應'(最多)。

最後,回答問題#1,沒有它應該是更簡單:)

希望這有助於 布賴恩

相關問題