代码重构的场景总结

作者: 奔跑吧李博 | 来源:发表于2018-10-09 18:11 被阅读56次

    核心思想:拆细、公用

    重构可以是修改变量名、重新安排目录这样简单的物理重构,也可以是抽取子函数、精简冗余设计这样稍许复杂的逻辑重构。但均不改变现有代码的功能。

    了解敌人——丑陋的代码
    • 臃肿的类
      开发者缺乏对最基本的编码原则,即“单一职责原则”(SRP)的理解。开发者不去思考这些功能是不是应该放在这同一个类中,导致这些类会变得很臃肿,造成一个类几千行,让下一个接盘侠欲哭无泪。

    • 臃肿的方法
      好几十上百行的一个函数堆在一块,用面向过程的思想来写代码。

    • 函数参数过多
      函数参数过多会导致调用者对方法难以理解,参数弄混。想象一下一个函数连续传5个int值参数,能分清谁是谁吗?建议可以将参数组成一个对象传入。

    • 层层嵌套的判断
      如果逻辑不复杂尽量减少if-else的分支包裹,他人太难阅读。比如不满足条件了直接return,不走其他代码,这样可以减少一层嵌套。

    • 满篇跑的常量值
      一个类里面出现各种未命名的常量值。0,1,200等等铺天盖地。这种状态码意义改了,改代码会把你改哭的。难道就不能先声明一个统一的常量变量来使用吗。

    • 模棱两可的命名
      不能根据名字一眼看懂它的功能的命名不是一个好命名。当然生僻的单词除外。模糊的,没有功能意义的命名会给阅读造成很大困难。

    重构之道

    • 分拆大函数: Break Method
      当函数比较大了,就可以根据功能节点分拆成多个小函数,也许其中的小函数还可以公用。比如结算购物车,包括计算各类商品的总价,再计算折扣,再计算满减优惠,如果一个方法执行完,那么别人要只要逻辑就要从头到尾读一遍。而分别拆分成三个,一眼就能看出这段逻辑先后做了什么。写方法切忌一口吃一个胖子。

    • 封装到父类:
      如果多各类要执行相似的功能和代码,可以把该方法放到它们的父类中,或者提取出来成业务工具类。

    • Move Method----方法迁移
      遵守“单一职责”原则,当类中的方法不适合放在当前类中时,就应该为该方法寻找合适下家。移到与方法耦合大的类中。当一个方法被其他类使用比在它所在类中的使用还要频繁时,我们就需要使用迁移方法重构了——将方法迁移到更频繁地使用它的类中。

    • Move Field----搬移字段
      当在一个类中的某一个字段,被另一个类的对象频繁使用时,我们就应该考虑将这个字段的位置进行更改了

    • Extract Class----提炼类
      一个类如果过于复杂,做了好多的事情,违背了“单一职责”的原则,所以需要将其可以独立的模块进行拆分,当然有可能由一个类拆分出多个类。
      对类的细化也是为了减少代码的重复性,以及提高代码的复用性,便于代码的维护。

    • 提升方法、字段(Pull Up Method)
      将方法向继承链上层迁移的过程。用于一个方法被多个实现者使用时。在继承的体系中,当多个类使用了相同或类似的方法,就可以考虑将该方法抽取到基类,没有基类就创建一个。字段提升同方法。

    • 降低方法
      即父类抽象方法让多个子类实现。多个子类有相同的功能但是有各个具体的实现方法,那么这种封装就可以用多态性了,父类创建一个抽象方法,将方法实现降低到子类。

    • 重复代码的提炼
      有时候为了赶项目进度,尽快完成功能,会偷懒将实现功能的一片代码复制一遍,直接套用。这种把多余的删掉,保留一个,也许只需传一两个参数就可以封成一个方法供多处调用。

    • 重命名变量(类、方法、变量)
      这个很重要,可以不夸张地说,命名的水平就体现了编程能力的高低。在重构的过程中,当发现类名,方法名在当前版本不符合它的功能含义,就该考虑对其重新命名。

    • 补加注释
      对于全局变量,公用函数,逻辑复杂的地方添加注释,弥补之前的遗漏。

    • 将较长的判断或代码运算用临时变脸暂存

    if(stateCode = OK && datas != null && canShow)
    
    function(Math.random((num1-num2)*num3))
    

    如上这种长长的判断条件和参数会使 这种代码应该先将if判断条件写成一个变量,放入变量判断,将function参数写一个局部变量保存结果,再传入方法。

    • 使用泛型封装成统一的方法或类

    • 函数要避免过多的参数造成阅读的复杂性

    public void requestPhoneThirdRegister(String loginway, String nickname, String openId, String token, String expires, String phone, final CallBackimpl callBackimpl)
    

    用这样的方法直接传参数就太长了,严重降低代码可读性。我们可以将参数变量写到一个实体类中,通过构造方法初始化对象属性值,只需要传递一个对象就搞定,也解决了增减参数带来的变动问题。

    • 嵌套条件分支优化
         if(){
                if(){
                    if(){
    
                    }
                }
            }else{
    
            }
    

    相信大家也见识过不少这样的箭头代码,像怎么也解不开的死结。遇到这种代码,一定要尽可能要优化。通常做法:判断语句,if条件成立,执行代码块,诶,这样就生成了一个嵌套层级。
    优化的核心思想:直接判断不满足的条件,if条件成立,直接return,尽快跳出方法来减少嵌套的层级。
    第二种:将条件判读合并

    • 尽量避免双重否定的条件
        private boolean isChecked(){
            if(){
                return true;
            }
        }
    

    一个条件方法。

    if(!isChecked()){
          
    }
    

    然后用否定来判断这个条件,这样可能会一时之间转变不过来导致条件判断反了。当然头脑灵活的忽略这条。

    • 去除东北乱炖的Util类
      当我们在写代码中偶然间需要抽出公用方法时,一时之间找不到合适的类去放置,然后就随意地放进了XXUtil或XXManager类中。长此以往,该类所含功能越来越杂,dp和px转化在其中,屏幕尺寸相关方法在其中,日期转化在其中,加密的索性也放在其中,那有无网络,网络类型判断也加入吧。这不就像垃圾场了吗,各类杂物都堆在其中,不符合单一职责原则,应该按照如上的功能块分解成多个职责单一的类。类多不要紧,关键要做到职责单一。

    • 将满篇跑的魔鬼数字和字符串用定义的常量表示。
      如果只是某个类或者某个模块需要用到该常量,就声明到对应类中。如果是全局项目都会用到的常量,就提升到项目的常量配置文件中。

    相关文章

      网友评论

        本文标题:代码重构的场景总结

        本文链接:https://www.haomeiwen.com/subject/plpapftx.html