首頁  >  文章  >  php教程  >  【轉】PHP 雜談《重建-改善既有程式碼的設計》之一 重新組織你的函數

【轉】PHP 雜談《重建-改善既有程式碼的設計》之一 重新組織你的函數

WBOY
WBOY原創
2016-10-18 08:42:031163瀏覽
原文位址: PHP 雜談《重建-改善既有程式碼的設計》之一 重新組織你的函數
心智圖
 
點擊下圖,可以看大圖。

 
 介紹
 
我把我比較喜歡的和比較關注的地方寫下來和大家分享。上次我寫了一篇《php 跟老大的對話》。還是有很多疑問,這書幫了我不少的忙。
 
如果你比較繁忙,或是懶得看文字,建議你直接看截圖,也會有很大的收穫的。你可以透過比較截圖中的程式碼就能知道孰優孰劣了。
 
程式碼部分我為什麼用圖呢?因為我常用手機看代碼,所以博客園的代碼在手機裡亂七八糟的,還是看圖比較舒服。
 
 專業術語
 
我們畢竟是用英文字母編碼,所以用一些英語單字,更能顯示出我們的專業性。以下的英文單字,你如果掌握了,與其他coder交流的時候會更直接,更專業。 ——臭顯擺一下吧,呵呵。
「*」表示文中常提到的
 
inline:內嵌
function:函數
*method:方法
finely grained:細粒度的
rename:重新命名
query:查詢
temp:暫時(temporary)-一般指暫時變數
*extract:提取——我個人更喜歡翻譯成「提煉」
*duplicate:複製
split:剖解
variable:變數
factor:因素,因子
 
 重建原則
 
一、何謂重構?
     名詞形式:軟體內部結構的一種調整,目的是在不改變軟體之可察行為前提下,提高其可理解型性,降低其修改成本。
  動詞形式:使用一系列重構準則,在不改變軟體之可察行為前提下,調整其結構。
 
 二、為何重構 ?
  1、經常重構可以讓程式碼維持該有的形態。
  2、讓程式碼找到適合的位置。
  3、讓軟體更容易理解。
  4、可以找到bug。
  5、提高我們的編碼速度。

 三、重構的難題
  1、修改介面命名
    如果你的類別中的方法是public,那麼你在rename的時候,冒著很大的風險,你不知道到底有哪些模組在呼叫你的這個方法(我們經常的做法是在整個專案下做grep操作,然後逐一看各個模組的呼叫和邏輯)。 ——所以我們在寫類別的時候不管是屬性還是方法盡量做到private,避免介面開放。
 
  2、何時不該重構
    (1)重寫所有程式碼,而且現有程式碼實在太混亂,重構不如重寫。
    (2)計畫接近結束的時候,應該避免重構。我們可以把重構放到二期去解決。 

 

 程式碼的壞味道
  一、Duplicate Code
  1、同一個類,兩個方法含有相同表達式。
    解決方法:你可以Extract Method提煉重複程式碼,然後讓這兩個方法都呼叫這個Extract Method。
       2、兩個類,有類似的方法。
     解決方法:(1)把兩個類別的方法提出來,共同建構一個父類別。
             (2)刪除其中一個類別的方法,呼叫另一個類別的方法。
 二、Long Method
  1、短函數:程式碼閱讀費點力氣,因為我們必須經常轉換上下文去看看子程式做了什麼。但是讓small method容易理解的真正關鍵在於一個好的名字。讀者可以透過名字了解函數的作用,根本不必去看其中寫了些什麼。 ——早期的程式語言中,呼叫方法需要額外開銷,這使得coder不願意使用small method。但是現代的OO語言幾乎已經完全免除了process內的額外開銷(函數呼叫)。
 
  2、註釋地方提煉信號:每當感覺需要以註釋來說明點什麼的時候,我們就把需要說明的東西寫進一個獨立函數中,並以其用途命名。可以對一組或甚至短短一行程式碼做這件事。 ——只要函數名稱能夠解釋其用戶,我們也該毫不猶豫地那麼做。
 
"函數"理解為」做什麼「或」如何做「
 
  3、條件式和循環常常也是提煉訊號。
 
  4、《代碼整潔之道》的一個例子。我們可以想想!

 
三、Large Class
 
  1、Class內數個屬性變數有相同前綴或字尾,可使用Extract Class。
 
  2、Class內並非大多數變數使用屬性變量,可使用Extract Class。
  
  3、有太多程式碼,可Extract Class。
 
四、Long Parameter
  做成Introduce Parameter Object。 ——這個我不太贊同,因為我在使用別人方法的時候,我很少去看代碼實踐,更不要說去看裡面都用到了對象的那些屬性或者方法,取我想要的數據了。
 
五、Switch Statements
  1、少用switch語句。 ——問題在於duplication。當你加入新case的時候,你必須找到所有case並修改它們。
  
  2、用多態來取代它。做法:1.將switch進行Extract Method;2.MoveMethod把case裡的實作程式碼放到多態性的class裡。
 
六、 Comments
  試試用Extract Method,如果還不行,那你試試Rename Method。
 
當你感覺需要撰寫註釋,請先嘗試重構,試著讓所有註釋變得多餘。
 
  註釋一般用於將來的打算,還可以用於你並無十足把握的區域(為什麼做某事)。
 
 重新組織你的函數
 
  Long Method往往包含太多訊息,這些訊息又被錯綜複雜的邏輯掩蓋,不易鑑別。
 
一、Extract Method
狀況:我看見一個過長的函數或需要一段註解才能讓人理解用途的程式碼,那麼將這段程式碼放進一個獨立函數中,並讓函數名稱解釋改函數的用途。

 

動機:

簡短而有良好命名的函數:——finely grained

  1、復用機會大。

  2、函數讀起來像讀一系列comments。

  3、函數覆蓋容易。

重點:函數長度關鍵在於函數名稱和函數本體之間的語意距離。如果提煉動作可以強化程式碼的清晰度,那就去做吧。

作法:

  1、建立新函數,根據函數的意圖命名-以它「做什麼」命名,而不是以它「怎麼做」命名。

    =》 即使Extract Function 非常簡單,例如只是訊息或函數調用,只要新Function能夠以更好方式昭示程式碼意圖,你也應該提煉它。但如果你想不出更有意義的名稱,就別動它。

  2、將Extract的程式碼從Source Function 中Move到New Function。

二、Inline Method

  Method Body與Method Name一樣清楚易懂的時候,請Inline Method。

 

三、Inline Temp

一個臨時變量,只被一個簡單表達式賦值一次,而且賦值完也只使用了一次。 ——請Inline Temp

 

四、Replace Temp with Query

如果一個Temp變量,保存一個表達式,將這個表達式Extract Method。 ——這就是所謂的查詢式,query

 

動機:

  1、局部變數會使程式碼難以提煉。

  2、臨時變數會驅使你寫出更長的程式碼。如果改成query method,那麼class下的method,都可以得到這份資訊。 ——將會寫出更清晰的程式碼。

  3、Replace Temp with Query往往是你運用Extract Method之前必不可少的步驟。

作法:

  1、找出只被賦值一次的臨時變數。

    =>  如果臨時變數賦值超過一次,考慮使用Split Temporary Variable將它分割成多個變數。

  2、對Temp Variable賦值的右側部分,Extract到一個獨立函數中。

           =>  將Method聲明為private,以及日後如果有其他class用的時候再放開它(public或protected)。

  

如果程式碼組織良好,那麼你往往能發現更有效的最佳化方案。 ————如果性能真的很糟糕,那麼放回去也很容易。
 
五、Introduce Explaining Variable
 
將複雜表達式中(或其中一部分)的結果放進一個臨時變量,以此變數名稱來解釋表達式用途。
 

 
動機:
  表達式複雜且難以閱讀。在這種情況下,臨時變數可以幫助你將表達式分解為比較容易管理的形式。
  
 六、Split Temporator Variable
 
 某個臨時變數被賦值超過一次,它既不是循環變量,也不是集合變數。那麼針對每次賦值,創造一個獨立的,對應的臨時變數。

 

 

動機:

  1、如果臨時變數承擔多個責任,它就應該被替換為多個臨時變數。每個變數只承擔一個責任。

  2、同一個臨時變數承擔兩件不同的事情,會讓review變得糊塗。

六、Remove Assignments To Parameters
如果你的程式碼對參數進行賦值,那麼以一個臨時變數取代該參數的位置
 

 

七、Replace Method with Method Object

大型函數對局部變數的使用無法採用Extract Method。那麼將這個Method放進一個單獨物件中,如此一來,讓局部變數成為物件的filed,然後在同一個物件中將大型函數分解為數個小型Method。

 

 

動機:

  1、將相對獨立的程式碼從大型Method中Extract出來,就可以大幅提升程式碼的可讀性。

  2、一個Method中,局部變數氾濫成災,分解這個函數將會非常困難。

  3、Replace Method with Method Object 會將所有局部變數變成物件的值域。然後對這個新物件進行Extract Method了。

八、Substitute Algorithm
 
如果你想把某個演算法替換為另一個更清晰的演算法,那麼將Method Body替換為另一個演算法。 ——就是直接修改原來的Method Body。
 
動機:隨著對問題有了更多的了解,你發現一件事可以有更清晰的方式,就應該以較清晰的方式取代複雜方式。
 
 總結
 
這只是本書的一部分內容,我知道會有很多的coder應該有不同的觀點,我自己也是,有的很贊同,有的我也是不太贊同的。所以要「則其善之而從之,其不善之而改之」。
 
歡迎大家發表下自己的看法。

 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn