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);
做法:
临时变量多了会难以维护,所以尽量去掉所使用的临时变量。
程序以一个临时变量保存某一表达式的运算结果,将这个表达式提取到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用,新函数就可以被其他函数调用。
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; }
临时变量是暂时的,只能在所属函数中使用,所以需要写更长的函数才能访问到临时变量。把临时变量替换为一个查询,同一个类中所有函数都可以获得这份信息。
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) { ...... }
做法:
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);
如果临时变量承担多个责任,应该被分解成多个临时变量,每个临时变量承担一个责任。
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 "";
}