逻辑之美,从重构谈起

   在《重构 改善既有代码的设计》一书中,称一些不完美的,甚至写的很烂的程序叫做有“坏味道”。当程序有“坏味道”时我们就要对它进行重构。作为程序猿,做几次重构后你就会发现你喜欢上重构,不知道别人是不是,反正我是喜欢上重构了。重构是一种对逻辑的审查与修改的过程,在一次做完对一个系统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之美的书,而我仅仅等待的是《逻辑之美》。

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