
一、好代碼的定義
關于好代碼的定義,各路大神都給出了自己的定義和見解
-
整潔的代碼如同優美的散文,—— Grady Booch
-
任何一個傻瓜都能寫出計算機可以理解的代碼,唯有寫出人類容易理解的代碼,才是優秀的程式員,—— Martin Fowler
首先要達成一致,我們寫的代碼,除了用于機器執行產生我們預期的效果之外,更多的時候是給人讀的,可能是后續的維護人員,更多時候是一段時間后的作者本人,因此優雅面向不同的用戶有兩層含義的解讀,
1.對人而言,代碼的整潔,清晰的邏輯;
2.對機器而言,準確性、執行性能、例外處理機制等;
1. 有意義的命名
public List<int[]> getItem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x: theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
整體邏輯沒啥問題,讀完之后,就有很多問題在腦海中產生
1. theList中是存盤什么東西的陣列?
2. theList第一個值是做什么的?
3. 值4的意義又是什么?
4. 回傳的串列該怎么使用?
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
2. 優雅的注釋
1. 一些被注釋掉的代碼
//something code
//something code
2. 位置標記
//begin
someting code;
//end
3. 簽名標記
/** add by xiaoli*/
4. 非公用方法的javadoc
/**
* doSomething
*/
private void doSomething(){
}
5. 日志式注釋
/** add xx
* update sometimes
* update sometimes
* update sometimes
*/
6. 誤導性注釋
//此處怎樣xx
3. 優雅的函式
3.1 務必要短小
public String renderPageWithSetupAndTeardowns(Page page, boolean isSuite) throws Exception{
if(isTestPage(page)){
includeSetupAndTeardownPages(page,isSuite);
}
return page.getHtml();
}
3.2 只做一件事
3.3 抽象層級一致
//把大象裝進冰箱
public void frozenElephant(){
//1. 捕捉大象
//2. 運輸大象
//3. 打開冰箱
//4. 放入大象
//5. 關閉冰箱
}
public void frozenElephant(){
//1. 捕捉大象
catchElephant();
//2. 運輸大象
transportElephant();
//將大象放入冰箱
putElephantInRefrigerator();
}
public void catchElephant(){
}
public void transportElephant(){
}
public void putElephantInRefrigerator(){
//打開冰箱
//放入大象
//關閉冰箱
}
if(deletePage() == OK){
if(registry.deleteReference(page.name) == OK){
if(configKeys.deleteKey(page.name.makeKey) == OK){
logger.log("page deleted")
}else{
logger.log("configKey not deleted")
}
}else{
logger.log("deleteReference from registry failed")
}
}else{
logger.log("delete failed")
return Error;
}
try{
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey);
}catch(Exception e){
logger.log(e.getMessage());
}
3.5 使用第三方庫
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
三、代碼重構
1. 識別代碼的壞味道
1.1 重復的代碼
1.最單純的重復代碼就是“同一個類的兩個函式含有相同的運算式”,這時候需要做的就是采用提煉函式提煉出重復的代碼,然后讓這兩個地點都呼叫被提煉出來的那一段代碼
2.如果重復代碼只是相似而不是完全相同,需要先嘗試用移動陳述句重組代碼順序,把相似的部分放在一起以便提煉,
1.2 過長的函式
遵循這樣一條原則:每當感覺需要以注釋來說明點什么的時候,就把需要說明的東西寫進一個獨立函式中,并以其用途(而非實作手法)命名,可以對一組甚至短短一行代碼做這件事,哪怕替換后的函式呼叫動作比函式自身還長,只要函式名稱能夠解釋其用途,就要毫不猶豫地那樣做,關鍵不在于函式的長度,而在于函式“做什么”和“如何做”之間的語意距離,
1.百分之九十九的場合里,要把函式變短,只需使用提煉函式,找到函式中適合集中在一起的部分,將它們提煉出來形成一個新函式,
2.如果函式內有大量的引數和臨時變數,最終就會把許多引數傳遞給被提煉出來的新函式,導致可讀性幾乎沒有任何提升,此時可以經常運用以查詢取代臨時變數來消除這些臨時元素,引入引數物件和保持物件完整則可以將過長的引數串列變得更簡潔一些,
1.3 資料的可變性
對資料的修改經常導致出乎意料的結果和難以發現的bug,在一處更新資料,卻沒有意識到軟體中的另一處期望著完全不同的資料,于是出現難以預料的bug,往往比較難排查(需要排查資料流轉的整體鏈路),這就需要一些方法用于約束對資料的更新,降低資料可變性的風險,
1.可以用封裝變數來確保所有資料更新操作都通過很少幾個函式來進行,使其更容易統一監控和演進
2.如果一個變數在不同時候被用于存盤不同的東西, 可以使用拆分變數將其拆分為各自不同用途的變數,從而避免危險的更新操作,
1.4 模塊單一職責
所謂模塊化,就是力求將代碼分出區域,最大化區域內部的互動、最小化跨區域的互動,但是經常出現一個函式跟另一個模塊中的函式或者資料交流格外頻繁,遠勝于與所處模塊內部的交流,這就是模塊功能不單一的典型情況,
1.總看到某個函式為了計算某個值,從另一個物件那兒呼叫半打的取值函式,如果這個函式需要跟這些資料待在一起,那就使用移動功能把它移過去,
2.一個函式往往會用到幾個模塊的功能,那么它究竟該被置于何處呢?原則是:判斷哪個模塊擁有的此函式使用的資料最多,然后就把這個函式和那些資料擺在一起, 如果先以提煉函式將這個函式分解為數個較小的函式并分別置放于不同類中,上面的步驟就會比較容易完成,
2. 函式重構的方法
2.1 Extract Method
2.2 Inline Method
2.3 Replace Temp with Query
2.4 Inline Temp
2.5 Introduce Explaining Variable
2.6 Split Temporary Variable
2.7 Remove Assignments to Parameters
2.8 Replace Method with Method Object
四、小結
本文來自博客園,作者:古道輕風,轉載請注明原文鏈接:https://www.cnblogs.com/88223100/p/How-to-write-elegant-code.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/544143.html
標籤:其他
上一篇:一文詳解|如何寫出優雅的代碼
下一篇:高復用性自動化腳本設計實踐
