現(xiàn)在回到重構(gòu)--改善既有代碼的設(shè)計這本書。
3.4Long Parameter List(過長參數(shù)列)
如果“向既有對象發(fā)出一條請求”就可以取得原本位于參數(shù)列上的一份數(shù)據(jù),那么你應(yīng)該激活重構(gòu)準(zhǔn)則Replace Parameter with Method。上述的既有對象可能是函數(shù)所屬class內(nèi)的一個值域,也可能是另一個參數(shù)。你還可以用 Preserve Whole Object將來自同一對象的一堆數(shù)據(jù)收藏起來,并以該對象替換它們。如果某些數(shù)據(jù)缺乏合理的對象歸屬,可使用Introduce Parameter Object為它們制造出一個“參數(shù)對象”。
Replace Parameter with Methods(以函數(shù)取代參數(shù))
對象調(diào)用某個函數(shù),并將結(jié)果作為參數(shù),傳遞給另外一個函數(shù)。而接受該參數(shù)的函數(shù)也可以(也有能力)調(diào)用前一個函數(shù)。
動機
如果函數(shù)可以通過其它途徑(而非參數(shù)列)獲得參數(shù)值,那么它就不應(yīng)該通過參數(shù)取得該值。
縮減參數(shù)列的辦法之一就是,看看“參數(shù)接受端”是否可以通過“與調(diào)用端相同的計算”來取得參數(shù)攜帶值。如果調(diào)用端通過“其所屬對象內(nèi)部的另一個函數(shù)”來計算參數(shù),并在計算過程中“未曾飲用調(diào)用端的其它參數(shù)”,那么你就應(yīng)該將這個計算過程轉(zhuǎn)移到被調(diào)用端內(nèi),從而除去該項參數(shù)。如果你所調(diào)用的函數(shù)隸屬另一對象,而該對象擁有一個reference指向調(diào)用端所屬對象,前面所說的這些也同樣適用。
作法
1、如果有必要,將參數(shù)的計算過程提煉到一個獨立函數(shù)中。
2、將函數(shù)本體內(nèi)“對該參數(shù)的引用”替換為對“新函數(shù)的引用”。
3、每次替換后,修改并測試。
4、全部替換完成后,適用Remove Parameter將該參數(shù)去掉。
思考:
確實從實踐角度講,上面這種方法是一種很實用的重構(gòu)方法。確實是縮減了函數(shù)的參數(shù)個數(shù),并隱藏了一些中間結(jié)果。但是我認(rèn)為,在應(yīng)用這個方法的時候,還應(yīng)當(dāng)考慮這樣兩個問題:
1、當(dāng)中間函數(shù)(方法)被隱藏的時候,以這個中間函數(shù)的返回值為參數(shù)的那個函數(shù)名還能夠表述自己的用途嗎?
2、被修改的那個函數(shù)所處的具體語境是什么。因為在面向?qū)ο缶幊痰臅r代,單獨去考慮一個函數(shù)的情況是很少的。確保這個函數(shù)是否處在正確的位置上(如是否處在正確的類中)是必要的。
此間存在一個重要的例外。有時候你明顯不希望造成“被調(diào)用之對象”與“較大對象”間的某種依存關(guān)系。這時候?qū)?shù)據(jù)從對象拆解出來單獨作為參數(shù),也很合情合理。但是請注意其所引發(fā)的代價。如果參數(shù)列太長或變化太頻繁,你就需要重新考慮自己的依存結(jié)構(gòu)了。
Introduce Parameter Object(引入?yún)?shù)對象)
某些參數(shù)總是很自然的同時出現(xiàn),以一個對象取代這些參數(shù)。
你常會看到特定的一組參數(shù)總是一起被傳遞。可能有好幾個函數(shù)都使用這一組參數(shù),這些函數(shù)可能隸屬同一個class,也可能隸屬不同的classes。這樣一組參數(shù)就是所謂的Data Clump(數(shù)據(jù)泥團)。我們可以運用一個對象包裝所有這些數(shù)據(jù),再以該對象取代它們。
作法:
1、新建一個class,用以表現(xiàn)你想替換的一組參數(shù)。將這個class設(shè)為不可變的(不可被修改的,immutable)。
2、編譯。
3、針對使用該組參數(shù)的所有函數(shù),實施Add Parameter,以上述新建class之實體對象作為新添參數(shù),并將此一參數(shù)值設(shè)為null。
4、對于Data Clump(數(shù)據(jù)泥團)中的每一項(在此均為參數(shù)),從函數(shù)簽名式中移除之,并修改調(diào)用端和函數(shù)本體,令他們都改而通過“新建的參數(shù)對象” 取得該值。
5、每除去一個參數(shù),編譯并測試。
6、將原先的參數(shù)全部除去之后,觀察有無適當(dāng)函數(shù)可以運用Move Method搬移到參數(shù)對象中。
思考:
現(xiàn)在我有一個函數(shù)f,函數(shù)定義如下:
public string f(int i,int j,string s)
{
int newValue=i+j;
string result=s+":"+newValue.ToString();
return result;
}
現(xiàn)在我把這三個參數(shù)轉(zhuǎn)化為類對象,類名定義為MyParameter
public class MyParameter
{
int _i;
public int I
{
get { return _i; }
set { _i = value; }
}
int _j;
public int J
{
get { return _j; }
set { _j = value; }
}
string _s;
public string S
{
get { return _s; }
set { _s = value; }
}
public MyParameter(int i, int j, stirng s)
{
_i = i;
_j = j;
_s = s;
}
}
然后再我的代碼中這樣寫:
f(new MyParameter(3,2,"Result"));
發(fā)現(xiàn)什么問題了嗎?
1、好像參數(shù)并沒有減少,只不過是移動到了構(gòu)造函數(shù)中;
2、你從f參數(shù)中將會看不出f中到底需要什么東西(如果參數(shù)名稱體現(xiàn)了參數(shù)的用途的話)。
這說明:
1、雖然這是經(jīng)典的重構(gòu)方法,但是不能濫用,在使用的時候要謹(jǐn)慎考慮場景是否合適。
2、注意TDA原理,不要刻意產(chǎn)生太多的中間對象。
3、參數(shù)不能隨便合并或隱去,要特別注意領(lǐng)域模型,要切合領(lǐng)域模型所表述的意圖。
我個人認(rèn)為可以應(yīng)用的場景:
就是文中所說的DataRange,即適合于被轉(zhuǎn)換為參數(shù)對象的參數(shù)列具有通用的含義,并且概念層次比較低。
posted on 2007-07-10 22:16
littlegai 閱讀(288)
評論(0) 編輯 收藏 引用 所屬分類:
我的讀書筆記