重构研究:Remove Assignments to Parameters(移除对参数的赋值)
动机:
举一个JAVA的按值传递参数形式:
1 public static void triple(int arg) { 2 arg = arg + 3; 3 System.out.println("arg in triple:" + arg); 4 } 5 6 public static void main(String[] args) { 7 // TODO Auto-generated method stub 8 int x = 5; 9 triple(x); 10 System.out.println("x after triple:" + x); 11 }
此段代码输出信息为:
arg in triple:8
x after triple:5
这个比较好理解,如果传递的是对象的话:
1 public static String printWithDate(Calendar arg) { 2 return arg.get(Calendar.YEAR) + "-" + (arg.get(Calendar.MONTH) + 1) + "-" 3 + arg.get(Calendar.DAY_OF_MONTH); 4 } 5 6 public static void nextDateUpdate(Calendar arg) { 7 arg.add(Calendar.DAY_OF_MONTH, 1); 8 System.out.println("arg in nextDay:" + printWithDate(arg)); 9 } 10 11 public static void nextDateReplace(Calendar arg) { 12 arg = Calendar.getInstance(); 13 14 arg.add(Calendar.DAY_OF_MONTH, 1); 15 System.out.println("arg in nextDay:" + printWithDate(arg)); 16 } 17 18 public static void main(String[] args) { 19 // TODO Auto-generated method stub 20 Calendar c1 = Calendar.getInstance(); 21 nextDateUpdate(c1); 22 System.out.println("c1 after nextDay:" + printWithDate(c1)); 23 24 Calendar c2 = Calendar.getInstance(); 25 nextDateReplace(c2); 26 System.out.println("c2 after nextDay:" + printWithDate(c2)); 27 }
此段代码输出信息为:
arg in nextDay:2012-7-28 c1 after nextDay:2012-7-28 arg in nextDay:2012-7-28 c2 after nextDay:2012-7-27
可见,JAVA的参数传递都是按值传递的
如果在参数内赋值,第一:降低了代码的清晰度,而且混用了按值传递和按引用传递这两种参数的传递方式,你可能想在参数内赋值,然后在函数外再使用参数的最新值,这是不可能的,JAVA只采用按值传递;第二:如果参数传递的是对象,那可以对“被传入的对象”进行一些相关操作,这是没问题的,在函数外可以更新最新值,但是如果在函数内重新对“被传入的对象”赋值,那就跟函数外的“调用对象”失去联系。
做法:
1.在第一次对参数赋值的地方,建立一个临时变量,把待处理的参数赋给它
2.把之后对所有此参数的引用点,全部替换为此临时变量的引用
3.修改赋值语句,使其改为对新建临时变量赋值。
附带:如果代码的参数是传入对象的,请在函数调用后查看是否还有使用了这个对象,这极有可能造成函数执行的结果没有作用到对象上。如果需要返回的结果不止一个,可以试着把返回类型转成一个对象,把所有结果转为对象的变量;或者把一个函数拆分为多个函数,每个函数只返回一个结果
范例:
举个书中的例子:
源代码为:
1 private int discount(int inputVal, int quantity, int yearToDate) { 2 if (inputVal > 50) { 3 inputVal -= 2; 4 } 5 6 if (quantity > 100) { 7 inputVal -= 1; 8 } 9 10 if(yearToDate > 10000) { 11 inputVal -= 4; 12 } 13 14 return inputVal; 15 }
去掉对参数的赋值,修改后的代码为:
1 private int discount(int inputVal, int quantity, int yearToDate) { 2 int result = inputVal; 3 4 if (inputVal > 50) { 5 result -= 2; 6 } 7 8 if (quantity > 100) { 9 result -= 1; 10 } 11 12 if(yearToDate > 10000) { 13 result -= 4; 14 } 15 16 return result; 17 }
最后附带一下,如果在很大的函数中,不好查看是否有对参数重复赋值,可以先把参数设置成final类型,这样就可以检查参数是否被做了修改,不过这种做法本人比较懒,不经常写,除非函数内有引用了内部类对象才要写,修改代码如下:
1 private int discount(final int inputVal, final int quantity, 2 final int yearToDate) { 3 int result = inputVal; 4 5 if (inputVal > 50) { 6 result -= 2; 7 } 8 9 if (quantity > 100) { 10 result -= 1; 11 } 12 13 if (yearToDate > 10000) { 14 result -= 4; 15 } 16 17 return result; 18 }
浙公网安备 33010602011771号