巨型類Large Class
當一個類嘗試做的太多,它常常展示出過多的實例變量。當一個類有太多實例變量,重復代碼的出現就不遠了。
你可以提取類來打包一部分變量。選擇在部件中有意義的變量放在一起。例如,“存款總量”和“存款貨幣”很可能在同一部件中。更寬泛的說,在一個類中變量的某個子集共同的前綴和后綴預示着組成同一個部件的機會。如果這個部件有成為子類的意義,你會發現提取子類往往更容易。
有時一個類不會一直使用它全部的實例變量。如果如此,你可能可以提取類或者提取子類若干次。
相比於一個類有太多實例變量,一個類有太多代碼是重復代碼,混亂,死亡的黃金溫床。最簡單的解決方案是消滅類中的冗余。如果你有500行方法里面有很多相同的代碼,你也許可以從原始代碼里把他轉變為5個10行的代碼的方法還有10個兩行代碼 的方法。
對於一個擁有大量填充變量的類,對有大量代碼的類通常的解決方案都是提取類或提取子類。一個有用的技巧是判定客戶怎么使用類來提取接口。這可能會給你進一步分解類提供想法。
如果你的巨型類是GUI類,你可能需要將數據和行為移到分別的域對象。這可能需要在兩邊保留一部分重復數據並且保持數據同步。重復觀察到的數據(Duplicate Observed Data)提示了怎么做。在這種情況下,尤其是如果你在用比較老的抽象窗口工具包(AWT)組件,你可能通過移除GUI類,替代以Swing組件。
長參數列表Long Parameter List
在我們編程的早年里我們被教導傳入所有需要的參數作為慣例。這很好理解,因為替代方式是全局數據,而全局數據是壞的並且常常很痛。對象改變了這一狀況因為如果你有什么東西你需要的但是還沒有,你總是可以向其他類要求去為你獲取。這樣有類對象你不需要傳入方法需要的所有,取而代之你傳入足夠的這樣方法可以獲取它需要的所有。大多數方法需要的在方法的主類中可用。在面向對象編程里參數列表一般比傳統的編程小的多。
這很好,因為長參數列表難以理解,因為他們變得不一致並且難用,因為你永遠會改變他們當你需要更多的數據時。大多數改變通過傳入對象被移除,因為你更可能需要只是做幾個請求來獲取一片新數據。
用通過方法替代參數重構方法,當你可以在一個參數中通過對你已知的對象做一些請求來獲取數據。這個對象可能是一個域或者它可能是另一個參數。用保留整個對象來從一個對象獲取一組數據然后用對象取代之。如果你有若干數據項不屬於任何邏輯對象,用引入參數對象重構方法。
對做這寫改變有一個重要的例外。當你顯式的不希望從調用方到更大的對象產生依賴。在這樣的情況下,拆開數據,單獨作為參數發送是理性的,但注意引入的痛。如果參數列表太長或者改變太頻繁,你需要三思你的依賴架構。
發散的變化Divergent Change
我們結構化我們的軟件以使得改變更容易;畢竟,軟件就應該軟。當我們作改動的時候,我們希望我們可以跳到系統中一個清楚的點上來做改變。當你做不到這一點時,你在聞兩個緊密相關的臭味之一。
發散變化發生在一個類普遍的因不同原因有不同形式的改變。如果你看一個類,然后說."每當我有一個新數據庫我需要改變這三個方法;每當有一個新的金融工具(financial instrument)的時候,我需要改變這四個方法," 你可能遇到了兩個對象優於一個的時候。這樣每個對象只因為一種改變而改變。當然,你常常只在你已經添加了幾個心數據庫或者金融工具時才會發現。任何處理變量的變化,應該只修改一個類,並且所有在新類打出的字應該表達那個變量。把這個清理干凈,你需要鑒別所有改變特定分句的東西,然后用提取類把他們放在一起。