代码重构技巧总结

重构-改善既有代码的设计

何为重构:在对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
为何重构:代码结构的流失是有累积性的,如果开始就很难看出代码所表达的设计意图,那么后续的人就越难保护好其中的设计,就会导致越改越腐                      败的结果。所以,重构不仅可以让代码维持自己该有的形态和行为,也能让代码结构更加易于扩展,更加易于阅读维护。

第一章 简介
1.变量名:通用易懂,符合常用规定,便于阅读;任何傻瓜都能写出计算机可以理解的代码,但是能被人容易理解的代码才是优秀程序员的代码
2.消除重复代码
3.去除临时变量
4.方法抽取与内敛等
5.尽可能简单的表达条件逻辑
6.运用多态取代针对对象属性的不同逻辑,而非大量的if或者switch判断;
          a.状态模式;视类为某种状态
          b.策略模式;视类为某种方式
6. 编码中的常见方法措施:(不限以下几种)
          提取方法;
          移动方法;
          用多态替换条件;
          封装域;
          用状态/策略替换类型代码;

第二章 重构原则
1.使软件更容易理解:代码的两个读者:电脑和人。
2.提高编程的速度:良好的设计是快速开发的根本。
3.事不过三,三则重构
4.保留旧接口:类似Java的“已弃用”;


第三章 代码的坏味道(哪些代码可以重构)
1.重复代码:
    a.同一个类的两个函数含有相同的表达式(抽取出来)
    b.两个互为兄弟的子类内含有相同的表达式(可以存入超类)
2.过长函数:对象拥有短函数会活的更好更久;程序越长越难理解;
3.过大的类:可以将之分解
4.过长参数列:过多的参数难以理解,可以提取到另一个独立的对象之中;
5.过多的switch:面向对象的特征就该少用switch。可用多态!当然某个单一函数用多态就有点杀鸡用牛刀!
6.令人迷惑的暂时字段:不要定义未使用的暂时参数,增加阅读迷惑性.
7.过度耦合的消息链条:a.b.c.d这样的方法请求形式。
8.过多的注释:注释不能少,但是不能用来解释一段质量糟糕的代码!而是尽可能去优化糟糕的代码,将其做到容易理解!

 

第四节:重新组织数据
4.1 自封装字段
为这个字段建立取值/设值函数,并且只以这些函数来访问字段;

以下面两段差异的代码作为比较:

// 直接使用数据
private int low,high;
boolean includes(int arg){
    return arg >= low && arg <= hign;
}

 

// 间接使用数据
private int low,high;
boolean includes(int arg){
    return arg >= low && arg <= hign;
}
 
int getLow(){return low;}
int getHigh(){return high;}


上面两种方法没有谁对谁错之分,要看使用的场景谁更合适;间接访问变量的好处,子类可以通过覆写一个函数而改变获取数据的途径,可以更灵活的进行数据管理;

一旦拥有一个子类,上述所有动作的价值就可以提现出来:
 

class CappedRange extents IntRange{
    CappedRange (int low,int high,int cap){
        super(low,high);
        this.cap=cap;
    }
    private int cap;
     
    int getCap(){
        return cap;
    }
 
    int getHigh(){
        return Math.min(super.getHigh(),getCap());
    }
}


4.2 将值对象改为引用对象

场景:系统中有好很多地方引用某个对象,单这个对象保存少量不可修改的数据,而后,你想给这个对象加一些可修改的数据,并确保对任何一个对象的修改都能影响到所有引用此对象的地方。这时就需要将这个对象变成一个引用对象。(单例模式的场景)

4.3 以字面常量取代魔法数

一个包含业务意义的魔法数,如果没有说明业务意思,维护的人会一脸懵逼,为了方便理解,可以将其定义为有字面意义的常量;
 

// 男性
private static final String BOY = 1;
// 女性
private static final String GIRL = 0;


第五节:简化条件表达式
程序之中,复杂的条件表达式会使代码的复杂度上升,使其可读性下降。

5.1 分解条件表达式

如果一个条件表达式又长又难理解,我们可以将其分解为多个独立函数,并将原函数中对应的代码改为调用新建函数,从而更清澈的表达自己的意图。
 

// 分解前的示例
if(条件1 && 条件2 || 条件3){
     
}else{
     
}
// 分解后的示例
if(this.check()){
    this.methodA();
}else{
    this.methodB();
}
 
/**
* 添加详细的业务功能说明
*/
private Boolean check(){
    return 条件1 && 条件2 || 条件3;
}


5.2 合并条件表达式
 

// 合并前的示例
if(num < 20 ) return 0;
if(age> 100 ) return 0;
if(isBoy) return 0;

 

// 合并后的示例
if(this.check(1,1,true)){
     
}
 
/**
* 条件合并到方法中
*/
private Boolean check(int num,int age,boolean isBoy){
    if((num < 20) || (age> 100) || isBoy) return 0;
}



5.3 以卫语句取代嵌套添加表达式

 /**
    * 查询对应征单的主键id以及审批流程节点
    * @param levyOrderExamines
    * @return
    */
   private List<LevyOrderExamineDto> getLevyOrderApplyId(List<LevyOrderExamineDto>  levyOrderExamines){
       List<LevyOrderExamineDto> hasOrderApplyIdList = new ArrayList<>(levyOrderExamines.size());
       // 卫语句直接判断为空的分支情况
       if(CollectionUtils.isEmpty(levyOrderExamines)){
           return hasOrderApplyIdList;
       }
       List<String> levyOrderNos = new ArrayList<>(levyOrderExamines.size());
       levyOrderExamines.forEach(item -> {
           if (!levyOrderNos.contains(item.getLevyOrderNo())){
               levyOrderNos.add(item.getLevyOrderNo());
           }
       });
       if(CollectionUtils.isNotEmpty(levyOrderNos)){
           List<LevyOrderExamineDto> withApplyIdDataList = levyOrderApplyMapper.getLevyOrderApplyId(levyOrderNos);
           if(CollectionUtils.isNotEmpty(withApplyIdDataList)){
               hasOrderApplyIdList.addAll(withApplyIdDataList);
           }
       }
       return hasOrderApplyIdList;
   }


其实,重构的知识点远不止以上举例子的这些,这些只是小的技巧方法,但是这样做可以提高代码的可阅读和可维护性;正所谓“代码一时爽,维护火葬场”,易于阅读和理解的代码才是优质的代码,那些为了炫技写的深奥复杂,难以阅读的代码并不值得学习。


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值