1. 程式人生 > >讀書報告之《修改程式碼的藝術》 (II)續2

讀書報告之《修改程式碼的藝術》 (II)續2

這裡作為(II)的第二個續篇,繼續複雜的巢狀if else 的處理。 為了保持篇幅不會太長,以一篇新的文章形式給出。

化簡複雜的if else語句,基本的手段

  1. 針對頭重腳輕的if else,使用return快速返回,從而減少巢狀層數。
  2. 合併分支。有些分支的執行內容相同,往往意味著可以合併為一個分支
  3. 扁平化。

這裡給出最後一個舉例,也是從網上隨便搜尋摘錄的

原始程式碼


		List<TWorkFlowwork> wfwList=errorProcessingService.findWorkFlowworkByWorkType("7",workbillcode.getId()+"");
		boolean flag=false;
		if(wfwList!=null&&wfwList.size()>0){
			for(int i=0;i<wfwList.size();i++){
				TWorkFlowwork wfw=wfwList.get(i);
				if(wfw!=null){//當前待辦是原件校驗並且如果已經結束了則啟用原件校驗待辦
					if(wfw.getStatus()!=null&&!"".equals(wfw.getStatus())){
						if("1".equals(wfw.getStatus())){
							flag=true;
							break;
						}
					}
					
				}
			}
			if(!flag){//如果原件校驗待辦都結束了,則產生一條原件校驗待辦
				TWorkBillcode wb=errorProcessingService.findWorkBillcodeByParameters(flow.getBussid(),flow.getBusstype());
				wb.setIsmatchpage("1");
				errorProcessingService.updateWorkBillcode(wb);
			}
		}


老規矩,簡單點評一下這個程式碼:唉~~~~~~~
  • 魔幻數字"7",“1”
  • 大量的空物件判斷。 這個不是表示嚴謹,而是程式碼設計有問題
  • 極深的if else 巢狀,主要都是極端的頭重腳輕形式的if 語句
首先,if(wfwList!=null&&wfwList.size()>0){ 超級的頭重腳輕,採用return 直接返回 其次,for(int i=0;i<wfwList.size();i++){   TWorkFlowwork wfw=wfwList.get(i);  可以利用java的語法甜頭,或者說是慣用法,替換為for (TWorkFlowwork wfw : wfwList)
然後,if (wfw!=null) 又可以用衛語句處理,不過這裡不能使用return直接返回,而是應該用continue 最後,後面if status的判斷實際都可以合併起來
if(wfw.getStatus()!=null&&!"".equals(wfw.getStatus())
				&& "1".equals(wfw.getStatus())){
						flag=true;
						break;
			}
仔細分析,不難發現wfw.getStatus()!=null&&!"".equals(wfw.getStatus()) 根本是多餘的。 於是程式碼變成這個樣子
List<TWorkFlowwork> wfwList=errorProcessingService.findWorkFlowworkByWorkType("7",workbillcode.getId()+"");
		boolean flag=false;
		if(wfwList==null || wfwList.size()==0) { return; }
		for (TWorkFlowwork wfw : wfwList) {
			//當前待辦是原件校驗並且如果已經結束了則啟用原件校驗待辦
			if (wfw == null) { continue; }
			if("1".equals(wfw.getStatus())){
				flag=true;
				break;
			}
		}
		if(!flag){//如果原件校驗待辦都結束了,則產生一條原件校驗待辦
			TWorkBillcode wb=errorProcessingService.findWorkBillcoHideByParameters(flow.getBussid(),flow.getBusstype());
			wb.setIsmatchpage("1");
			errorProcessingService.updateWorkBillcode(wb);
		}


接下來,本來想對第一個迴圈做一個方法抽取,因為實際操作比較像查詢——查詢是否所有原件已經校驗結束。改成查詢之後,不僅含義上清楚到無需註釋,而且可以去掉討厭的標記變數flag以及wfwList為空的判斷。 可惜沒有全部程式碼,不知道這樣修改是否會產品副作用。因為對最後一段“如果原件校驗待辦都結束了,則產生一條原件校驗待辦”這個註釋無法拿捏得很準,這個“產生一條”是指產生下一條? 所以說,理想的情況是讓程式碼自注釋。如果寫了註釋,一定要維護程式碼的同時維護註釋,錯誤的註釋比沒有註釋更糟糕。不管如何,原本複雜的if else 我們已經大大簡化了。 最後再囉嗦一下,面試時程式碼的編寫確實是必不可少的一部分:從這份程式碼就可以看出
  • 原作者對java的基本語法不熟;// 迴圈語句很拙劣,可能是從C轉入沒多久
  • 之前系統的培訓過或者認真看過相關編碼的書; // 大量的魔幻數字,wfwList.size()==0 而不是isEmpty() 
  • 程式碼量不大。// 這個程式碼片段不長,卻非常費解。而且程式碼層次感不強,各種高層的介面和底層的介面雜糅在一起


最後的最後,做個簡單的總結。

這一部分主要是舉例討論複雜的鋸齒形 if else語句的處理。基本方法不外乎三個
  1. 針對頭重腳輕的if else,使用return快速返回,從而減少巢狀層數。
  2. 合併分支。有些分支的執行內容相同,往往意味著可以合併為一個分支
  3. 扁平化。
裡面的舉例,一般我是儘可能按照重構,一步步的列出。
  1. 修改if else 最忌憚的是天馬行空,自負自己對程式碼的理解,直接重新改寫條件語句。但另一方面,相信各位看官也注意到了,理解又是必不可少的,完全死死的做邏輯變形是異常繁瑣的(這個在第二個例子中尤為明顯),具體如何操作,不好意思,這就是"修改程式碼的藝術"。口才不行,修行還靠個人。
  2. 不要做不成熟的優化。相對來說,程式碼的清晰度高於效能的優化,而且很多時候兩者並不是衝突的,當代碼更清新了,往往有更好的優化方案。
  3. 舉例中的一些程式碼風格,比如return快速返回,不是每個人都能接受。求同存異,這也是個人座右銘。
  4. 大千世界,簡化 if else的方法肯定不止上面幾種。但這幾種還是很實用,歡迎個人崇拜,不要懷疑者,不要腦殘粉。(玩笑大笑,勿當真,只是想說,"不要怕,不要悔",剛開始時,儘管做,不要太多懷疑)

最後,如果對重構還有興趣,可以看一看《重構--我的遺留系統改進之路》,這是一個培訓ppt,寫得不錯。這裡推薦一下