重构的常用手法

重构常用的几种手法

extract method

replace temp with query
introduce parameter object
replace method with method object
introduce explaining Variable
decompose conditional

具体实践

1、extract method

代码提炼,用于把一整段代码提炼到一个方法。这是最常用的重构手法,当我看见一个过长的函数或者一段需要注释才能理解用途的代码,我就会将这段代码放进一个独立函数中。这样的函数的粒度很小,函数之间彼此复用的机会就更大。

public void eat(){
   System.out.println("淘米");
   System.out.println("煮饭");
   
   System.out.println("洗菜");
   System.out.println("煮菜");

   System.out.println("拿碗筷");
   System.out.println("打饭");
   
   System.out.println("吃饭");
}

上述是吃饭可能经历的一些步骤,从逻辑上来讲其中淘米和煮饭可以使用Extract Method

提炼为一个方法。

Extract Method的操作步骤:

1、选中需要提炼的代码块

2、点击右键->选中Refactor->Extract Method

3、输入提取后的函数名

提炼后的结果:

public void eat(){
   cookRice();

   System.out.println("洗菜");
   System.out.println("煮菜");

   System.out.println("拿碗筷");
   System.out.println("打饭");

   System.out.println("吃饭");
}

private void cookRice() {
   System.out.println("淘米");
   System.out.println("煮饭");
}

2、replace temp with query

使用查询替换临时变量,解决代码提炼过程中的参数多问题。因为如果代码中存在很多的临时变量,那么通过Extract Method提取的函数,就会有大量的参数,replace temp with query可以解决这个问题。 

 原

double getPrice(int originPrice,int random) {
   int basePrice = 100 - random;
   int discount = 2 * random;
   int type = 3 + random;
   double discountFactor;
   if (basePrice > 50 && discount > 10 && type > 6) {
      discountFactor = 0.95;
   } else {
      discountFactor = 0.98;
   }
   return originPrice * discountFactor;
}

其中,discountFactor可以通过Extract Method提炼为一个方法。

提炼结果:

double getPrice(int originPrice,int random) {
   int basePrice = 100 - random;
   int discount = 2 * random;
   int type = 3 + random;
   double discountFactor = getDiscountFactor(basePrice, discount, type);
   return originPrice * discountFactor;
}

private double getDiscountFactor(int basePrice, int discount, int type) {
   double discountFactor;
   if (basePrice > 50 && discount > 10 && type > 6) {
      discountFactor = 0.95;
   } else {
      discountFactor = 0.98;
   }
   return discountFactor;
}

但是我们发现,这个getDiscountFactor的参数有三个,但是我们不希望有那么多的参数。(因为实际开发中可能会更多)。那么这个时候我们可以使用replace temp with query

来降低提炼函数的参数个数。

replace temp with query具体步骤:

1、使用Extract Method提取basePrice,discount,type的代码

double getPrice(int originPrice,int random) {
   int basePrice = getBasePrice(random);
   int discount = getDiscount(random);
   int type = getType(random);
   double discountFactor;
   if (basePrice > 50 && discount > 10 && type > 6) {
      discountFactor = 0.95;
   } else {
      discountFactor = 0.98;
   }
   return originPrice * discountFactor;
}
...

2、去掉临时变量

double getPrice(int originPrice,int random) {
   double discountFactor;
   if (getBasePrice(random) > 50 && getDiscount(random) > 10 && getType(random) > 6) {
      discountFactor = 0.95;
   } else {
      discountFactor = 0.98;
   }
   return originPrice * discountFactor;
}

3、Extract Method提取discountFactor相关代码

double getPrice(int originPrice,int random) {
   double discountFactor = getDiscountFactor(random);
   return originPrice * discountFactor;
}

private double getDiscountFactor(int random) {
   double discountFactor;
   if (getBasePrice(random) > 50 && getDiscount(random) > 10 && getType(random) > 6) {
      discountFactor = 0.95;
   } else {
      discountFactor = 0.98;
   }
   return discountFactor;
}

此时我们可以看到,使用replace temp with query后再提炼getDiscountFactor方法,就没有那么多的参数了,从而完成了减少方法参数数量的目标。


 3、introduce parameter object

引入参数对象,解决方法参数过多的情况。

比如下面的方法,通过多个参数获取用户信息,可以看到参数非常多,这种时候我们可以使用introduce parameter object,引入对应的参数对象,解决参数多的问题。

public List<User> listPageUser(int pageIndex,int PageSize,int age,int sex,int status) {
   List<User> userList = userDao.getList(pageIndex, PageSize, age, sex, status);
   return userList;
}

具体操作:

1、选中需要构建参数对象的参数

2、点击右键->选中Refactor->Introduce Parameter Object

3、输入提取后的参数对象名

public List<User> listPageUser(UserQueryRequest userQueryRequest) {
   List<User> userList = userDao.getList(userQueryRequest.getPageIndex(), userQueryRequest.getPageSize(), userQueryRequest.getAge(), userQueryRequest.getSex(), userQueryRequest.getStatus());
   return userList;
}
public class UserQueryRequest {
   private final int pageIndex;
   private final int pageSize;
   private final int age;
   private final int sex;
   private final int status;
   ...
}

结果就是从5个参数,变成了1个参数对象。


4、replace method with method object

使用方法对象来替换原方法,比如原来是一个传很多参数的方法,我们把这个方法变成为一个对象,对象里面提供具体逻辑,这里还是为了解决参数过多的问题。

 比如:

原:
public class Person {
    
    public static void main(String[] args) {
       Person person = new Person();
       System.out.println(person.getComputerPrice(100, 50, 10, 6, 2));
    }

   public double getComputerPrice(int originPrice,int basePrice,int discount,int type,int quantity) {
      double discountFactor;
      if (basePrice > 50 && discount > 10 && type > 6) {
         discountFactor = 0.95;
      } else {
         discountFactor = 0.98;
      }
      return originPrice * discountFactor * quantity;
   }
}

我们创建一个新的类Computer,然后把这些参数变成Computer类的属性

如下:

public class Person {
   public static void main(String[] args) {
      Computer computer = new Computer(100, 50, 10, 6, 2);
      System.out.println(computer.getPrice());
   }
}


public class Computer {
   
   private final int originPrice;
   private final int basePrice;
   private final int discount;
   private final int type;
   private final int quantity;
   
   public Computer(int originPrice, int basePrice, int discount, int type, int quantity) {
      this.originPrice = originPrice;
      this.basePrice = basePrice;
      this.discount = discount;
      this.type = type;
      this.quantity = quantity;
   }

   public double getPrice() {
      double discountFactor;
      if (basePrice > 50 && discount > 10 && type > 6) {
         discountFactor = 0.95;
      } else {
         discountFactor = 0.98;
      }
      return originPrice * discountFactor * quantity;
   }
}

这样重构后,方法的参数个数就明显降下来了,而且具体的计算逻辑也放到了合适的类。

此时我们可以轻松的对getPrice进行Extract Method提炼,而不用考虑临时变量的问题。


5、introduce explaining Variable

引入注释性变量。将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。

 比如:

if ((platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize >0){
    //do smothing
}

处理后

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize >0;
if(isMacOs && isIEBrowser && wasInitialized() && wasResized){
    //do smothing
}

把if里面的表达式提取了出来,用boolean的参数来描述,便于理解。


 6、decompose conditional

分解条件表达式内容,将if里面的代码提炼出来,构成一个独立函数。将then段落和else段落都提炼出来,各自构成一个独立函数。

 比如

if (date.before(SUMMER_START) || date.after(SUMMER_END)){
    charge = quantity * _winterRate + _winterServiceCharge;
}else {
    charge = quantity * _summerRate;
}

处理后:

if (notSummer(date)){
    charge = winterCharge(quantity);
}else {
    charge = summerCharge(quantity);
}

private boolean notSummer(Date date) {
    return date.before(SUMMER_START) || date.after(SUMMER_END);
}

private double summerCharge(int quantity) {
    return quantity * _summerRate;
}

private double winterCharge(int quantity) {
    return quantity * _winterRate + _winterServiceCharge;
}

if和then里面的代码我们通过Extract Method分别提取到了summerCharge和winterCharge

方法,从而条件判断后执行的代码看起来非常简洁,易于理解。

总结

 代码重构能持续提升代码质量,使代码便于维护。其中掌握好重构常用的手法非常关键,

大家可以多多实践,相信大家的代码质量会有明显的提升。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厚土燎原

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值