天天看點

重構-改善既有代碼的設計-簡化函數調用

Rename Method 函數改名

問題

函數的名稱未能揭示函數的用途。

方法

修改函數名稱。

動機

好的函數需要有一個清晰的函數名。保證一看就懂

Add Parameter 添加參數

某個函數需要從調用端得到更多資訊。

為此函數添加一個對象參數,讓該對象帶進函數所需資訊。

如果發現缺少參數,當然就需要添加參數。但是在添加之前,先思考是否一定要添加。或者實用參數對象

Remove Parameter 移除參數

函數本體不再需要某個參數。

将該參數去除。

别人在調用的時候,面對這個無用的參數可能無所适從

Separate Query from Modifier 将查詢函數和修改函數分離

某個函數既傳回對象狀态值,又修改對象狀态。

建立2個不同的函數,其中一個負責查詢,另一個負責修改。

首先這個函數做了兩件事,就很值得重構了。其次 不光要查詢,還要修改。這個函數會成為bug之源。

考慮并發情況

Parameterize Method 令函數攜帶參數

若幹函數做了類似的工作,但在函數本體中卻包含了不同的值。

建立一個單一函數,以參數表達那些不同的值。

你可能會發現這樣的2個函數:它們做着類似的工作,但因少數幾個值緻使行為略為不同。這種情況下,你可以将這些各自分離的函數統一起來,并通過參數來處理那些變化,用以簡化問題。這樣的修改可以去除重複代碼,并提高靈活性,因為你可以用這個參數處理更多的變化情況。

Replace Parameter with Explicit Methods 以明确函數取代參數

你有一個函數,其中完全取決于參數值而采取不同行為。

針對該參數的每個可能值,建立一個獨立函數。

(以明确函數取代參數)恰恰相反于 (令函數攜帶參數)。如果某個參數有多種可能的值,而函數内又以條件表達式檢查這些參數值,并根據不同參數值做出不同的行為,那麼就應該使用本項重構。

Preserve whole object 保持對象完整

你從某個對象中取出若幹值,将它們作為某一次函數調用時的參數。

改為傳遞整個對象。

有時候,你會将來自同一對象的若幹項資料作為參數,傳遞給某個函數。這樣做的問題在于:萬一将來被調用函數需要新的資料項,你就必須查找并修改對此函數的所有調用。如果你把這些資料所屬的整個對象傳給函數,可以避免這種尴尬的處境,因為被調用函數可以向那個參數對象請求任何它想要的資訊。不過事情總有2面:如果你傳的是數值,被調用函數就隻依賴于這些數值,而不依賴它們所屬的對象。

Replace Parameter with Methods 以函數取代參數

對象調用某個函數,并将所得結果作為參數,傳遞給另一個函數。而接受該參數的函數本身也能夠調用前一個函數。

讓參數接受者去除該項參數,并直接調用前一個函數。

如果函數可以通過其他途徑獲得參數值,那麼它就不應該通過參數取得該值。過長的參數列會增加程式閱讀者的了解難度,是以應該盡可能縮短參數列的長度。

Introduce Parameter Object 引入參數對象

某些參數總是很自然地同時出現。

以一個對象取代這些參數。

本項重構還可以帶給你更多好處。當你把這些參數組織到一起後,往往很快可以發現一些可被移至建立類的行為。通常,原本使用那些參數的函數對這一組參數會有一些共通的處理,如果将這些共通行為移到新對象中,你可以減少很多重複代碼。

Remove setting Method 移除設定函數

類中的某個字段應該在對象建立時被設值,然後就不再改變。

去掉該字段的所有設值函數。

如果你為某個字段提供了設值函數,這就暗示這個字段值可以被改變。如果你不希望在對象建立之後此字段還有機會被改變,那就不要為它提供設值函數。這樣你的意圖會更加清晰,并且可以排除其值被修改的可能性。

如果你保留了間接通路變量的方法,就可能經常有程式員盲目使用它們。這些人甚至會在構造函數中使用設值函數。

Hide Method 隐藏函數

有一個函數,從來沒有被其他任何類用到。

将這個函數修改為private。

重構往往促使你修改函數的可見度。提高函數可見度的情況很容易想象:另一個類需要用到某個函數,是以你必須提高該函數的可見度。但是要指出一個函數的可見度是否過高,就稍微困難一些。理想狀态下,你可以使用工具檢查所有函數,指出可被隐藏起來的函數。即使沒有這樣的工具,你也應該時常進行這樣的檢查。

   一種特别常見的情況是:當你面對一個過于豐富、提供了過多行為的接口時,就值得将非必要的取值函數和設值函數隐藏起來。尤其當你面對的是一個簡單封裝的資料容器時,情況更是如此。随着越來越多行為被放入這個類,你會發現許多設值/取值函數不再需要被公開,是以可以将它們隐藏起來。如果你把取值/設值函數設為private,然後在所有地方都直接通路變量,那就可以放心移除取值/設值函數了。

Replace Constructor with Factory Method 以工廠函數取代構造函數

你希望在建立對象時不僅僅是做簡單的建構動作。

将構造函數替換為工廠函數。

就是在派生子類的過程中以工廠函數取代類型碼。你可能常常需要根據類型碼建立相應的對象,現在,建立名單中還得加上子類,那些子類也是根據類型碼來建立。然而由于構造函數隻能傳回單一類型的對象,是以你需要将構造函數替換為工廠函數。

   此外,如果構造函數的功能不能滿足你的需要,也可以使用工廠函數代替它。工廠函數也是Change Value to Reference (将值對象改為引用對象)的基礎。你也可以令你的工廠函數根據參數的個數和類型,選擇不同的建構行為。

Encapsulate Downcast 封裝向下轉型

某個函數傳回的對象,需要由函數調用者執行向下轉型(downcast)。

将向下轉型動作移到函數中。

向下轉型也許是無法避免的,但你仍然應該盡可能少做。如果你的某個函數傳回一個值,并且你知道所傳回的對象類型比函數簽名所昭告的更特化,你便是在函數使用者身上強加了非必要的工作。這種情況下你不應該要求使用者承擔向下轉型的責任,應該盡量為他們提供準确的類型。

以上所說的情況,常會在傳回疊代器或集合的函數身上發生。此時你就應該觀察人們拿這個疊代器幹什麼用,然後針對性地提供專用函數。

Replace Error Code with Exception 以異常取代錯誤碼

某個函數傳回一個特定的代碼,用以表示某種錯誤情況。

改用異常。

可以使用更好的錯誤處理方式:異常。它清楚地将“普通程式”和“錯誤處理”分開了,這使得程式更容易了解:代碼的可了解性應該是我們追求的目标。

Replace Exception with Test 以測試取代異常

面對一個調用者可以預先檢查的條件,你抛出一個異常。

修改調用者,使它在調用函數之前先做檢查。

異常的出現是程式語言的一大進步。但是,就像許多好東西一樣,異常會被濫用,進而變得不再讓人愉快。“異常”隻應該被用于異常的、罕見的行為,也就是那些産生意料之外的錯誤的行為,而不應該成為條件檢查的替代品。如果你可以合理期望調用者在調用函數之前檢查某個條件,那麼就應該提供一個測試,而調用者應該使用它。

Java架構師之路:https://jq.qq.com/?_wv=1027&k=5B436TY

繼續閱讀