邏輯之美,從重構談起

       在《重構 改善既有代碼的設計》一書中,稱一些不完美的,甚至寫的很爛的程序叫做有“壞味道”。當程序有“壞味道”時我們就要對它進行重構。作爲程序猿,做幾次重構後你就會發現你喜歡上重構,不知道別人是不是,反正我是喜歡上重構了。重構是一種對邏輯的審查與修改的過程,在一次做完對一個系統40%代碼的重構後,我把代碼量減少了90%,但是代碼變得更容易理解了,而且可擴展性更強了,那時覺得非常有成就感。腦子還瞬間蹦出來一個詞——邏輯之美,但是感覺這應該是一本書的名字,但是網上搜了一下竟然沒有這本書《邏輯之美》。

    下面,我們來看一個我剛剛重構過的方法(部分註釋是我爲了讀者容易理解加上去的,單詞Indicator意思是指標的意思)。

/* 功能:下面方法功能是對js框架dhtmlx的表格控件dhtmlxgrid對象一次刷新
  * 背景:本方法的應用背景是對mygrid內多行進行拖動排序,排序原理是先獲取行的初始位置,目標位置,然後獲取以數組形式獲取mygrid中的數據(行id,每一個單元格的數據),將數組進行排序後重新填充進原表格mygrid
  * 參數:參數array是將要重新填充進表格的數組數據,參數mygrid的是將要操作的dhtmlxgrid對象
   */
function reCreatMygrid(array,mygrid){   //刷新新的指標列表
    mygrid.clearAll(false);   //不清除表頭
    var cellIndicatorArrayLength = mygrid.getColumnsNum()+1;   //單位指標的數組長度(所有列的值加上行id)
   var newArray=[];  //用來存儲指標列表內容
    var newArrayId=[];  //用來存儲新列表的Id
   /*
   * 因爲是提供給所有已定義dhtmlxgrid表格應用接口,所以每個表格的列數有差異
   */
   if(cellIndicatorArrayLength==7){    //如果表格總共有6列
           for( var i=0;i<array.length;i=i+7){
                 newArray.push([array[i],array[i+1],array[i+2],array[i+3],array[i+4],array[i+5]]);
                 newArrayId.push(array[i+6]);      
         }
   }else if(cellIndicatorArrayLength==6){    //如果表格總共有5列
           for( var i=0;i<array.length;i=i+6){
                 newArray.push([array[i],array[i+1],array[i+2],array[i+3],array[i+4]]);
                 newArrayId.push(array[i+5]);      
         }
   }else if(cellIndicatorArrayLength==5){     //如果表格總共有4列
           for( var i=0;i<array.length;i=i+5){
                 newArray.push([array[i],array[i+1],array[i+2],array[i+3]]);
                 newArrayId.push(array[i+4]); 
         }
   }else if(cellIndicatorArrayLength==4){
          for( var i=0;i<array.length;i=i+4){
                 newArray.push([array[i],array[i+1],array[i+2]]);
                 newArrayId.push(array[i+3]);      
         }
   }else if(cellIndicatorArrayLength==3){
          for( var i=0;i<array.length;i=i+3){
                 newArray.push([array[i],array[i+1]]);
                 newArrayId.push(array[i+2]);      
         }
   }
   //將數據填充進表格(dhtmlxgrid提供的接口)
   mygrid.parse(newArray,"jsarray" );
   /*
   * dhtmlxgrid提供的數組填充方式不能爲其賦予行id,初始化後爲默認id,即1,2,3……
   * 現在我們必須把每行原有的id賦給每一行
   */
   for( var j=0;j<mygrid.getRowsNum();j++){
         mygrid.setRowId(j, newArrayId[j]);
   }
 }

       上面方法這是我一年前寫的。這不,前兩天這塊出問題了,當mygrid的行過多的時候(其實也不多就60多行),當使用拖拽排序的時候,就會出現問題。什麼問題呢?首先,拖動之後瀏覽器會出現崩潰現象;其次,經過我調試,發現問題就在最後一個循環裏面,即dhtmlxgrid的原生的爲行設置行id的方法setRowId會失效,就這麼一個循環,但是設置了行id後,並不是理想狀態的。我不想去查setRowId的原因了,因爲我覺得我的這個方法本身就很爛,我想重構它。

       對,就是重構。

       重構的首要任務是解決bug,我得使用另一種方法初始化mygrid,即不用Array數據了,我打算使用Json格式 (dhtmlx控件基本都支持HTML table, xml,array,json),因爲json格式可以再填充表格數據的時候同時賦給每行id值,它絕對可以解決目前的bug。經過查閱了dhtmlxgrid的幫助文檔,我成功的完成任務,代碼如下:

function reCreatMyrightgrid(array,mygrid){   //刷新新的指標列表
   mygrid.clearAll(false);   //不清除表頭
   var cellIndicatorArrayLength = mygrid.getColumnsNum()+1;   //單位指標的數組長度(所有列的值加上行id)
   //var newArray=[];  //用來存儲指標列表內容
   //var newArrayId=[];  //用來存儲新列表的Id
   var rowsArray = [];   //存放行數據的數組[{"id":行id,"data":本行每一列的數據數組}]
   var dataAll = {};
   if(cellIndicatorArrayLength==7){    //如果表格總共有5列
         for( var i=0;i<array.length;i=i+7){
                //newArray.push([array[i],array[i+1],array[i+2],array[i+3],array[i+4],array[i+5]]);
                //newArrayId.push(array[i+6]);
            rowsArray.push({"id":array[i+6], "data":[array[i],array[i+1],array[i+2],array[i+3],array[i+4],array[i+5]]});
      }
   }else if(cellIndicatorArrayLength==6){    //如果表格總共有5列
         for( var i=0;i<array.length;i=i+6){
            //newArray.push([array[i],array[i+1],array[i+2],array[i+3],array[i+4]]);
            //newArrayId.push(array[i+5]);  
            rowsArray.push({"id":array[i+5], "data":[array[i],array[i+1],array[i+2],array[i+3],array[i+4]]});
      }
   }else if(cellIndicatorArrayLength==5){     //如果表格總共有4列
         for( var i=0;i<array.length;i=i+5){
            //newArray.push([array[i],array[i+1],array[i+2],array[i+3]]);
            //newArrayId.push(array[i+4]);
        rowsArray.push({"id":array[i+4], "data":[array[i],array[i+1],array[i+2],array[i+3]]});
      }
   }else if(cellIndicatorArrayLength==4){
         for( var i=0;i<array.length;i=i+4){
            //newArray.push([array[i],array[i+1],array[i+2]]);
            //newArrayId.push(array[i+3]);
            rowsArray.push({"id":array[i+3], "data":[array[i],array[i+1],array[i+2]]});
      }
   }else if(cellIndicatorArrayLength==3){
         for( var i=0;i<array.length;i=i+3){
            //newArray.push([array[i],array[i+1]]);
            //newArrayId.push(array[i+2]);
            rowsArray.push({"id":array[i+2], "data":[array[i],array[i+1]]});
      }
   }
   dataAll.rows=rowsArray;
   mygrid.parse(dataAll,"json" );
   //mygrid.parse(newArray,"jsarray");
   //for(var j=0;j<mygrid.getRowsNum();j++){  //爲新列表附上行id
   //    mygrid.setRowId(j, newArrayId[j]);
   //}
}

       處理bug的任務已經完成,爲什麼還留有這個多註釋呢?別急,其實重構纔剛剛開始。

剛纔稱其爲重構,其實我們只是選擇了一個更合適的方案來代替原來的方案。但是代碼中這一串if else語句明顯帶有壞味道,在性能方面可以使用switch代替;以後要是有其他列數的表格需要排序,我們還得爲它再添加一個else if?No,這就是壞味道。

       就像《重構 改善既有代碼的設計》中提到的某一種程序員,我盯着屏幕開始發呆……

       過了幾分鐘,思路慢慢有了,在過了幾分鐘,好了,問題解決了。對,我就要刪除這些if else語句,下面是再次重構後的代碼:

function reCreatMyrightgrid(array,mygrid){   //刷新新的指標列表
   mygrid.clearAll(false);   //不清除表頭
   var cellIndicatorArrayLength = mygrid.getColumnsNum()+1;   //單位指標的數組長度(所有列的值加上行id)
   var rowsArray = [];   //存放行數據的數組[{"id":行id,"data":本行每一列的數據數組}]
   var dataAll = {};
   for( var i=0;i<array.length;i=i+cellIndicatorArrayLength){
         var data = [];
         for( var n=0;n<cellIndicatorArrayLength-1;n++){
               data.push(array[i+n]);
         }
         rowsArray.push({"id" :array[i+cellIndicatorArrayLength-1],"data":data});
   }
   dataAll.rows=rowsArray;
   mygrid.parse(dataAll,"json" );
}

       到此,對這個方法的重構告一段落。這次重構的效果是很明顯的,單從代碼量角度看,刪除了20/36,最後剩了僅僅16行代碼;其次,它解決了很重要的bug;最後它淨化了代碼,提供了更好的擴展。所以,這次重構是成功的。

       是的,邏輯之美就是如此之美!曾記得邏輯之美在我腦海中時,還沒有《研究之美》這本以XX之美命名的書,隨後可能還會陸續出來其他XX之美的書,而我僅僅等待的是《邏輯之美》。

發佈了34 篇原創文章 · 獲贊 23 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章