1. 提炼函数
这种情况应该很多人都遇到过,编程中不要有大量的重复代码,解决办法就是去提炼到一个单独的函数中。
void A() { ..... System.out.println("name" + _name); } void B() { ..... System.out.println("name" + _name); }
更改为↓
void A() { .... } void B() { .... } void printName(String name) { System.out.println("name" + name); }
void printOwing(double amount){ String _name; //print details System.out.println("name:" +_name); System.out.println("amount:"+amount); }
更改为↓
void printDetails(double amount, String _name) { System.out.println("name:" +_name); System.out.println("amount:"+amount); }
2. 内联函数
在函数调用点插入函数本体,然后移除该函数
int getRating(){ return (moreThanFiveLateDeliveries())?2:1; } boolean moreThanFiveLateDeliveries(){ return _numberOfLateDeliveries>5; }
做法:
检查函数,确定它不具多态性,如果子类继承了这个函数,就不要将此函数内联,因为子类根本无法覆写一个根本不存在的函数。找出这个函数的所有被调用点。将这个函数的所有被调用点都替换为函数本体编译,测试删除该函数的定义3. 内联临时变量
如果你对一个变量只引用了一次,那就不妨对他进行一次重构。将所有对该变量的引用动作,替换为对它赋值的那个表达式本身int basePrice = order.basePrice(); return (basePrice > 100);
更改为↓
return (order.basePrice() > 1000);
做法:
检查给临时变量赋值的语句,确保等号右边的表达式没有副作用。如果这个临时变量并未被申明为final,那么将它申明为final,然后编译,这可以检查临时变量是否只会赋值一遍。找到该临时变量的所有引用点,将他们替换为“为临时变量赋值的表达式”。修改完所有的引用点以后,删除临时变量的申明和赋值语句。编译,测试。4.以查询取代临时变量临时变量多了会难以维护,所以尽量去掉所使用的临时变量。
程序以一个临时变量保存某一表达式的运算结果,将这个表达式提取到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用,新函数就可以被其他函数调用。
int area = _length * _width; if (area > 1000) return area * 5; else return area *4;
更改为↓
if (area() > 1000) return area() * 5; else return area() *4; int area() { return _length * _width; }
临时变量是暂时的,只能在所属函数中使用,所以需要写更长的函数才能访问到临时变量。把临时变量替换为一个查询,同一个类中所有函数都可以获得这份信息。
做法:简单:找出只被赋值一次的临时变量。如果这个临时变量被赋值超过一次,将它分割成多个变量。将该临时变量声明为final。编译,可确保该临时变量只被赋值一次。将对该临时变量赋值的语句的等号的右边提炼到一个独立函数中首先将函数声明成private,以后会有更多类需要使用它,那时在放开保护确保提炼出来的函数无任何副作用,及该函数并不修改任何对象内容,有则提炼编译,测试。在该临时变量身上实施内联临时变量double getPrice(){ int basePrice = _quantity*_itemPrice; double discountFactor; if(basePrice >1000) discountFactor = 0.95; else discountFactor = 0.98; return basePrice*discountFactor; } double getPrice(){ //检查是否赋值一次 //final double discountFactor = discountFactor(); //if(basePrice() >1000) discountFactor = 0.95; // else discountFactor = 0.98; return basePrice()*discountFactor(); } private int basePrice() { return _quantity*_itemPrice;//使用内联临时变量把basePrice的引用点去掉。然后去掉临时变量的声明 } private double discountFactor(){ if(basePrice()>1000) return 0.95; else return 0.98; }
5. 引入解释性变量
跟上面那个相反,如果使用函数变得很复杂,可以考虑使用解释型变量了。
将该复杂表达式(或其中一部分)的结果放入一个临时变量,以此变量名称来解释表达式用途
if ((platform.toUpperCase().indexOf("mac") > -1) && (brower.toUpperCase().indexOf("ie") > -1) && wasInitializes() && resize > 0) { ...... }
更改为↓
final boolean isMacOS = platform.toUpperCase().indexOf("mac") > -1; final boolean isIEBrowser = brower.toUpperCase().indexOf("ie") > -1; final boolean wasResized = resize > 0; if (isMacOS && isIEBrowser && wasInitializes() && wasResized) { ...... }
做法:
声明一个final临时变量,将待分解的复杂表达式中的一部分动作的运算结果赋值给它。将表达式中的运算结果这一部分,替换为上述临时变量。如果被替换的这一部分在代码中重复出现,可以卓一替换。编译,测试。处理表达式其余部分。
6. 分解临时变量某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。针对每次赋值,创造一个独立,对应的临时变量。
double temp = 2*(_height+_width); System.out.println(temp); temp = _height*_width; System.out.println(temp); 更改为↓ final double perimeter = 2*(_height+_width); System.out.println(perimeter); final double area = _height*_width; System.out.println(area);
如果临时变量承担多个责任,应该被分解成多个临时变量,每个临时变量承担一个责任。做法:在待分解临时变量的声明及其第一次被赋值处,修改其名称。如果赋值语句是[i=i+某表达式]形式,意味着这是个结果收集变量,就不要分解。结果收集变量的作用通常是累加、字符串接合,写入流或者向集合添加元素。将新的临时变量声明为final。以该临时变量的第二次赋值动作为界,修改此前对该临时变量的所有引用点,让他们引用新的临时变量。在第二次赋值处,重新声明那个临时变量。编译,测试。重复操作,每次都在声明处对临时变量改名,并修改下次赋值之前的引用点
7. 移除对参数的赋值
参数传入函数中,应该尽量避免对其进行更改。
代码对一个参数进行赋值,以一个临时变量取代该参数的位置。
int discount (int inputVal, int quantity, int yearToDate) { if (inputVal > 50) inputVal -= 2; } 更改为↓ int discount (int inputVal, int quantity, int yearToDate) { int result = inputVal; if (result > 50) result -= 2; }
另外,函数中声明的临时变量最好只被赋值一次,如果超过一次就考虑再声明变量对其进行分解了。
一个函数也不应该太长,如果太长首先影响理解,其次包含的步骤太多会影响函数复用。做法是将里面的步骤提取为很多小函数,并且函数命名要体现出函数做了什么,清晰明了。做法:
建立一个临时变量,把待处理的参数赋予它。
以对参数的赋值为界,将其后所有对此参数的引用点,全部替换为‘对此临时变量的引用’。
修改赋值语句,使其改为对新建的临时变量赋值。
编译,测试。如果代码的语义是按引用传递的,在调用端检查调用后是否还是用这个参数,也要检查有多少个按引用传递的参数被赋值后又被使用,尽量只以return方式返回一个值,如果返回的值不止一个,把返回的值改成对象,或为每个返回值设计对应的独立函数。
int distinct(int inputVal,int quantity,int yearToDate){ if(inputVal >50) inputVal =2; if(quantity >100) inputVal =1; if(yearToDate >10000) inputVal =4; return inputVal; } 更改为↓ //以临时变量取代对参数的赋值动作 //为参数加上final,强调遵循不对参数赋值这一惯例 int distinct(final int inputVal,final int quantity,final int yearToDate){ int result = inputVal; if(inputVal >50) result =2; if(quantity >100) result =1; if(yearToDate >10000) result =4; return result; }
8.以函数对象取代函数
大型函数,对局部变量的使用让无法使用提炼函数
将这个函数放入单独对象中,这样局部变量就变成了对象中的字段,可以在同一个对象中将大型函数分解成多个小型函数。
做法:
建立一个新类,根据待处理函数的用途,以这个类命名。
在新类中建立一个final字段,用来保存原先大型函数所在的对象,将这个字段称为源对象,同时,原函数的每个临时变量和每个参数,在新类中建立一个对应的字段保存。
在新类中建立一个构造函数,接收源对象及原函数的所有参数作为参数。
在新类中建立一个compute()函数。
将原函数的代码复制到compute()中,如果需要调用源对象的任何函数,通过源对象字段调用。
编译。
将旧函数的函数本体替换为这样一条语句:‘创建上述新类的一个新对象,而后调用其中的compute()函数’。
范例:
class Account{ int gamma (int inputVal ,int quantity,int yearToDate){ // int importantValue1 = (inputVal*quantity)+ delte(); // int importantValue2 = (inputVal*quantity)+100; // if((yearToDate - importantValue1)>100) // importantValue2 -=20; // int importantValue3 = importantValue2 * 7; // return importantValue3 - 2 * importantValue1; // } return new Gamma(this, inputVal, quantity, yearToDate).compute(); } } class Gamma{ //提供final保存源对象 private final Account _account; private int inputVal; private int quantity; private int yearToDate; private int importantValue1; private int importantValue2; private int importantValue3; //加入构造函数 public Gamma(Account source, int inputVal, int quantity, int yearToDate) { super(); this._account = source; this.inputVal = inputVal; this.quantity = quantity; this.yearToDate = yearToDate; } //把旧函数的放入 int compute(){ int importantValue1 = (inputVal*quantity)+ _account.delte(); int importantValue2 = (inputVal*quantity)+100; //抽函数 importantThing(); int importantValue3 = importantValue2 * 7; return importantValue3 - 2 * importantValue1; } void importantThing() { if((yearToDate - importantValue1)>100) importantValue2 -=20; } }
9.替换算法
将函数本体替换成另一个算法。
String foundPersion(String [] people){ for(int i = 0; i<people.length;i++){ if (people[i].equals("Don")) { return "Don"; } if(people[i].equals("Join")){ return "Join"; } if(people[i].equals("Kent")){ return "Kent"; } } return ""; } 更改为↓ String foundPersion(String [] people){ List candidates = Arrays.asList(new String []{"Don","Join","Kent"}); for(int i = 0; i<candidates.size();i++){ if(candidates.contains(people[i])){ return people[i]; } } return ""; }