Total Pageviews

2011/06/22

Refactoring: Decompose Conditional

Motivation

if-else條件判斷式,一直是程式看起來很複雜的地方。當功能更複雜,條件式就會更多,判斷式就會顯得又臭又長。無論是程式的可讀性,或是可維護性,都大大的降低。另外,在測試的時候(如code coverage test),也會增加測試時間。


Mechanics
  • 將condition 的部份extract到獨立的method.
  • 將if-else的部份,extract到獨立的method.

Example

Before Refactor


 public List doPrint(String evdcCdStart, String evdcCdEnd) throws FDCDataAccessException {  
      List params = new ArrayList();  
      StringBuffer sql = new StringBuffer();  
      sql.append(" SELECT EVADE_CD, EVADE_NM FROM Nigt042 ");  
      String where = " WHERE ", and = " ";  
      if(StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd)){  
           sql.append(where).append(and).append(" EVADE_CD between ?1 and ?2 ");  
           params.add(evdcCdStart);  
           params.add(evdcCdEnd);  
           where = " ";  
           and = " AND ";  
      }else if(StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isEmpty(evdcCdEnd)){  
           sql.append(where).append(and).append(" EVADE_CD >= ?1 ");  
           params.add(evdcCdStart);  
           where = " ";  
           and = " AND ";  
      }else if(StringUtils.isEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd)){  
           sql.append(where).append(and).append(" EVADE_CD <= ?1 ");  
           params.add(evdcCdEnd);  
           where = " ";  
           and = " AND ";  
      }  
      sql.append(" ORDER BY EVADE_CD ");  
      return Nigt042Dao.queryNativeSQL(new Nigt042(), sql.toString(), params.toArray());  
 }  

從上述code snippet可以看出有三段判斷式

判斷式1: StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd)

判斷式2: StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isEmpty(evdcCdEnd)

判斷式3: StringUtils.isEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd)

為了讓if-else邏輯判斷增加可讀性,分別將此三的判斷式抽離成三個private method,並賦予有意義的名字,此三個method分別為:

before extract after extract
StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd) hasStartAndEndCode
StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isEmpty(evdcCdEnd) onlyHasStartCode
StringUtils.isEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd) onlyHasEndCode



After Refactor


 public List doPrint(String evdcCdStart, String evdcCdEnd) throws FDCDataAccessException {  
      List params = new ArrayList();  
      StringBuffer sql = new StringBuffer();  
      sql.append(" SELECT EVDC_CD, EVDC_NM FROM NIGT042 ");  
      String where = " WHERE ", and = " ";  
      if(hasStartAndEndCode(evdcCdStart, evdcCdEnd)){  
           sql.append(where).append(and).append(" EVDC_CD between ?1 and ?2 ");  
           params.add(evdcCdStart);  
           params.add(evdcCdEnd);  
           where = " ";  
           and = " AND ";  
      }else if(onlyHasStartCode(evdcCdStart, evdcCdEnd)){  
           sql.append(where).append(and).append(" EVDC_CD >= ?1 ");  
           params.add(evdcCdStart);  
           where = " ";  
           and = " AND ";  
      }else if(onlyHasEndCode(evdcCdStart, evdcCdEnd)){  
           sql.append(where).append(and).append(" EVDC_CD <= ?1 ");  
           params.add(evdcCdEnd);  
           where = " ";  
           and = " AND ";  
      }  
      sql.append(" ORDER BY EVDC_CD ");  
      return nigt042Dao.queryNativeSQL(new Nigt042(), sql.toString(), params.toArray());  
 }  
 private boolean onlyHasEndCode(String evdcCdStart, String evdcCdEnd) {  
      return StringUtils.isEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd);  
 }  
 private boolean onlyHasStartCode(String evdcCdStart, String evdcCdEnd) {  
      return StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isEmpty(evdcCdEnd);  
 }  
 private boolean hasStartAndEndCode(String evdcCdStart, String evdcCdEnd) {  
      return StringUtils.isNotEmpty(evdcCdStart) && StringUtils.isNotEmpty(evdcCdEnd);  
 }  

No comments: