2011-11-10 36 views
78

我有一個需要30個參數的方法。我把這些參數放到一個類中,這樣我就可以將一個參數(類)傳遞給方法。在重構的情況下傳遞一個封裝所有參數的對象是否完全正確,即使它包含了所有參數。爲了重構目的而只有屬性的類可以嗎?

+0

下面的答案很好。我總是爲此設立一堂課。你使用自動屬性? http://msdn.microsoft.com/en-us/library/bb384054.aspx – Harv

+0

否則稱爲POD(普通舊數據)類型。 – new123456

+17

雖然許多給出的答案都很好,並且將這些參數重構成更容易處理的事情確實是一個好主意,但我會說,這種方法需要30個不同的數據來完成它的事實是表示它做得太多了。但是,再一次,我們沒有看到有關的方法,甚至沒有知道它的目的。 –

回答

74

這是一個好主意。例如,數據合同通常是如何在WCF中完成的。

該模型的一個優點是,如果添加一個新參數,該類的使用者不需要爲了添加參數而改變。

當大衛赫弗南提到,它可以幫助自我文檔代碼:

FrobRequest frobRequest = new FrobRequest 
{ 
    FrobTarget = "Joe", 
    Url = new Uri("http://example.com"), 
    Count = 42, 
}; 
FrobResult frobResult = Frob(frobRequest); 
+0

太好了。我的印象是,只有擁有屬性而沒有方法的課程沒用。 – Xaisoft

+0

好的第二點。 – Xaisoft

+2

如果它只包含數據成員,我更喜歡使它成爲結構體。使用結構給人的印象是它只是數據。 – Yousf

10

這是一個很好的想法和問題的一個非常常見的解決方案。超過2或3個參數的方法指數級地變得越來越難以理解。

將所有這些封裝在一個類中,代碼更加清晰。當然

params.height = 42; 
params.width = 666; 
obj.doSomething(params); 

當你有很多的參數,基於位置identication另一種方法是簡單的可怕:因爲你的屬性有名稱,你可以寫自我記錄的代碼是這樣的。

另一個好處是可以在接口合同中添加額外的參數,而無需在所有呼叫站點強制進行更改。然而,這並不總是像看起來那麼微不足道。如果不同的呼叫站點對新參數要求不同的值,那麼與使用基於參數的方法相比,它們更難追捕它們。在基於參數的方法中,添加新參數會在每個調用站點上強制更改以提供新參數,並且您可以讓編譯器執行全部查找工作。

+1

偉大而優秀的回答讓我感覺良好。 – Xaisoft

3

你也可以考慮使用結構而不是類。

但是你想要做的是非常普通,一個好主意!

+0

我其實想過使用一個結構,但我很好奇,如果我使用一個結構會有什麼缺點。 – Xaisoft

+0

結構不被推薦用於那麼多領域 –

+0

爲什麼選David?領域的數量與它有什麼關係?只是好奇。 –

5

30參數亂七八糟。我認爲有屬性的課程會更漂亮。您甚至可以爲適合相同類別的參數組創建多個「參數類」。

62

雖然這裏的其他答案正確地指出,傳遞一個類的實例比傳遞30個參數要好,但請注意,大量參數可能是潛在問題的症狀。例如,很多時候靜態方法會增加參數的數量,因爲它們應該一直是實例方法,並且您傳遞了很多可以在該類的實例中更容易維護的信息。

或者,查找將參數分組到較高抽象級別的對象中的方法。將一堆無關的參數轉儲到一個類中是IMO的最後一招。

請參閱How many parameters are too many?瞭解更多關於此的一些想法。

+0

在什麼意義上這些參數是不相關的?它們都被這種方法使用。這是一個非常強大的關係。更重要的是,堆棧中的參數通常更適合狀態。考慮多線程。 –

+12

沒有看到OP的代碼就無法回答,但我不同意這一點,僅僅是因爲兩個值在方法中一起使用,他們有很強的關係。如果這是真的,面向對象設計最終意味着創建一個擁有應用程序中所有可能屬性的大類。 – RedFilter

+0

不,你是對的,不一定相關。但也不一定無關。所以,就像你說的那樣,需要看到代碼才能確定。 –

9

Martin Fowler在他的書重構稱這Introduce Parameter Object。有了這個引用,很少有人會說這是一個壞主意。

+1

是的,但對於30個參數,其他地方有什麼不對勁,必須先修復 – manojlds

+1

@manojlds:確實,但你必須從某個地方開始...... –

14

雖然重構參數對象本身並不是一個壞主意,但它不應該用來隱藏需要從其他地方提供的30個數據的類仍然可能是代碼異味的問題。引入參數對象重構可能應該被視爲在更廣泛的重構過程中的一個步驟,而不是該過程的結束。

它沒有真正解決的關注點之一就是Feature Envy。傳遞參數對象的類是否對另一個類的數據非常感興趣這一事實並不表明可以將對這些數據進行操作的方法移至數據所在的位置?確定屬於一組的方法和數據集合並將它們分組到類中真的會更好,因此可以增加封裝並使您的代碼更加靈活。

經過幾次迭代拆分行爲和它操作的數據到不同的單元中,您應該會發現不再有任何具有大量依賴的類,這總是一個更好的最終結果,因爲它會使您的代碼更加柔順。

+0

+1對於功能羨慕,很好的答案。 – RedFilter

25

這是一個很好的開始。但是現在你已經有了這個新課程,可以考慮把你的代碼從頭到腳地翻出來。移動將該類作爲參數的方法移動到新類中(當然,將原始類的實例作爲參數傳遞)。現在你已經有了一個很大的方法,單獨在一個類中,將它分解成更小,更易於管理和可測試的方法會更容易。其中一些方法可能會回到原來的類,但是一個公平的塊可能會留在你的新類中。您已經超出Introduce Parameter ObjectReplace Method with Method Object

擁有30個參數的方法是一個非常強大的信號,表明該方法太長且太複雜。太難調試,太難測試。所以你應該做些什麼,介紹參數對象是一個很好的開始。

+4

這絕對是重要的!創建這些屬性包非常重要,因爲它是使用自己的方法創建新類的第一步,而且您幾乎總能找到屬於您的新類的方法 - 尋找它們!我認爲這是這個小組中最關鍵的答案,它應該接近頂端。 –

3

不管你是否重構,使用Plain Old Data類都是合理的。我很好奇你爲什麼認爲它可能不是。

+0

我並不完全記得,但我認爲當我剛纔在這裏提到某個地方時,我正在創建一個只有屬性的類時,它在當時是被忽視的。在第二點上,你是否說只有不改變的參數應該在方法中傳遞,換句話說,如果方法改變了參數,它不應該作爲參數傳入。 – Xaisoft

+0

只有屬性的類可能是一種難聞的氣味(請參閱史蒂夫羅伯特漢姆的答案),它表明某些應該是「完整」類的東西。一個好兆頭是,如果你最終不止一次地使用類似的類。然而,情況並非總是如此,在30場和30場參數方法之間的折騰中,傾向於前者的呼聲良好。此外,它可以成爲開展「全班」課程的開始。 –

+0

...我正在刪除我對不變性的評論,因爲我只是在考慮更多這類公共方法(其中「請求」對象描述調用者的意圖)。這裏改變「請求」可能會導致混淆。在一次性案例中,更易於修改和構建。不變性僅僅意味着用一個30個參數的構造函數和一個調用來代替30個參數的調用,所以不會有勝利。 –

3

也許C#4.0的可選和命名參數是一個很好的選擇嗎?

無論如何,你所描述的方法也可以很好地抽象出程序行爲。例如,您可以在Interface中使用一個標準的SaveImage(ImageSaveParameters saveParams)-函數,其中ImageSaveParameters也是一個接口,並且可以根據圖像格式具有其他參數。例如,JpegSaveParameters擁有Quality-屬性,而PngSaveParameters擁有BitDepth-屬性。

這就是Paint.NET中的保存對話框,它是一個非常真實的例子。

3

正如前面所說:這是應該做的正確的一步,但考慮到如下太:

  • 你的方法可能過於複雜(你應該考慮將其分成多個方法,甚至把它變成一個單獨的類)
  • 如果你創建了參數類,使其immutable
  • 如果有很多的參數可以爲空,也可能存在一些默認值,則可能需要使用builder pattern爲類。
0

這裏有很多很棒的答案。我想補充我的兩分錢。

參數對象是一個好的開始。但還有更多可以做到的事情。考慮以下(紅寶石示例):

/1 /而不是簡單地分組所有參數,看看是否可以有意義的參數分組。您可能需要多個參數對象。

def display_line(startPoint, endPoint, option1, option2) 

可能變得

def display_line(line, display_options) 

/2/Parameter對象可以具有更少數量比原來數量的參數的特性。

def double_click?(cursor_location1, control1, cursor_location2, control2) 

可能成爲

def double_click?(first_click_info, second_click_info) 
         # MouseClickInfo being the parameter object type 
         # having cursor_location and control_at_click as properties 

這樣的使用將幫助您發現有意義添加行爲,這些參數對象的可能性。你會發現他們儘早地擺脫了他們最初的Data Class smell。 : - )

相關問題