重构研究: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     }

 

posted on 2012-07-27 08:04  低调点  阅读(601)  评论(0)    收藏  举报

导航