邏輯之美,從重構談起

   在《重構 改善既有代碼的設計》一書中,稱一些不完美的,甚至寫的很爛的程序叫做有“壞味道”。當程序有“壞味道”時我們就要對它進行重構。作爲程序猿,做幾次重構後你就會發現你喜歡上重構,不知道別人是不是,反正我是喜歡上重構了。重構是一種對邏輯的審查與修改的過程,在一次做完對一個系統40%代碼的重構後,我把代碼量減少了90%,但是代碼變得更容易理解了,而且可擴展性更強了,那時覺得非常有成就感。腦子還瞬間蹦出來一個詞——邏輯之美,但是感覺這應該是一本書的名字,但是網上搜了一下竟然沒有這本書《邏輯之美》。
   下面,我們來看一個我剛剛重構過的方法(部分註釋是我爲了讀者容易理解加上去的)。
/*
* 功能:下面方法功能是對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 xmlarrayjson),因爲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之美的書,而我僅僅等待的是《邏輯之美》。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章